diff options
-rw-r--r-- | java/res/values-xlarge/bools.xml | 1 | ||||
-rw-r--r-- | java/res/values/bools.xml | 1 | ||||
-rw-r--r-- | java/res/xml/prefs.xml | 1 | ||||
-rw-r--r-- | java/src/com/android/inputmethod/latin/Settings.java | 7 | ||||
-rw-r--r-- | java/src/com/android/inputmethod/latin/UserDictionary.java | 20 | ||||
-rw-r--r-- | native/src/defines.h | 6 | ||||
-rw-r--r-- | native/src/unigram_dictionary.cpp | 89 | ||||
-rw-r--r-- | native/src/unigram_dictionary.h | 12 |
8 files changed, 89 insertions, 48 deletions
diff --git a/java/res/values-xlarge/bools.xml b/java/res/values-xlarge/bools.xml index abacfa18b..9fb670c54 100644 --- a/java/res/values-xlarge/bools.xml +++ b/java/res/values-xlarge/bools.xml @@ -21,6 +21,7 @@ <!-- Whether or not Popup on key press is enabled by default --> <bool name="default_popup_preview">false</bool> <bool name="config_enable_show_settings_key_option">false</bool> + <bool name="config_enable_show_subtype_settings">false</bool> <bool name="config_enable_show_voice_key_option">false</bool> <bool name="config_candidate_highlight_font_color_enabled">false</bool> </resources> diff --git a/java/res/values/bools.xml b/java/res/values/bools.xml index 84b0fe182..8742676ad 100644 --- a/java/res/values/bools.xml +++ b/java/res/values/bools.xml @@ -31,6 +31,7 @@ <bool name="default_recorrection_enabled">true</bool> <bool name="config_long_press_comma_for_settings_enabled">true</bool> <bool name="config_enable_show_settings_key_option">true</bool> + <bool name="config_enable_show_subtype_settings">true</bool> <bool name="config_enable_show_voice_key_option">true</bool> <bool name="config_candidate_highlight_font_color_enabled">true</bool> </resources> diff --git a/java/res/xml/prefs.xml b/java/res/xml/prefs.xml index 0eee06031..47b3b4589 100644 --- a/java/res/xml/prefs.xml +++ b/java/res/xml/prefs.xml @@ -73,6 +73,7 @@ <!-- TODO: Filter subtypes by IME in SubtypeEnabler --> <!-- TODO: Maybe use this only for phone? --> <PreferenceScreen + android:key="subtype_settings" android:title="@string/language_selection_title" android:summary="@string/language_selection_summary"> <intent diff --git a/java/src/com/android/inputmethod/latin/Settings.java b/java/src/com/android/inputmethod/latin/Settings.java index b8590a76e..3f604a381 100644 --- a/java/src/com/android/inputmethod/latin/Settings.java +++ b/java/src/com/android/inputmethod/latin/Settings.java @@ -53,6 +53,7 @@ public class Settings extends PreferenceActivity public static final String PREF_VOICE_SETTINGS_KEY = "voice_mode"; public static final String PREF_INPUT_LANGUAGE = "input_language"; public static final String PREF_SELECTED_LANGUAGES = "selected_languages"; + public static final String PREF_SUBTYPES = "subtype_settings"; public static final String PREF_PREDICTION_SETTINGS_KEY = "prediction_settings"; public static final String PREF_QUICK_FIXES = "quick_fixes"; @@ -119,6 +120,12 @@ public class Settings extends PreferenceActivity getPreferenceScreen().removePreference( getPreferenceScreen().findPreference(PREF_VIBRATE_ON)); } + + final boolean showSubtypeSettings = getResources().getBoolean( + R.bool.config_enable_show_subtype_settings); + if (!showSubtypeSettings) { + getPreferenceScreen().removePreference(findPreference(PREF_SUBTYPES)); + } } @Override diff --git a/java/src/com/android/inputmethod/latin/UserDictionary.java b/java/src/com/android/inputmethod/latin/UserDictionary.java index 7a94ae480..e03f56498 100644 --- a/java/src/com/android/inputmethod/latin/UserDictionary.java +++ b/java/src/com/android/inputmethod/latin/UserDictionary.java @@ -21,6 +21,7 @@ import android.content.ContentValues; import android.content.Context; import android.database.ContentObserver; import android.database.Cursor; +import android.net.Uri; import android.provider.UserDictionary.Words; public class UserDictionary extends ExpandableDictionary { @@ -80,7 +81,7 @@ public class UserDictionary extends ExpandableDictionary { * @TODO use a higher or float range for frequency */ @Override - public synchronized void addWord(String word, int frequency) { + public synchronized void addWord(final String word, final int frequency) { // Force load the dictionary here synchronously if (getRequiresReload()) loadDictionaryAsync(); // Safeguard against adding long words. Can cause stack overflow. @@ -99,7 +100,22 @@ public class UserDictionary extends ExpandableDictionary { new Thread("addWord") { @Override public void run() { - contentResolver.insert(Words.CONTENT_URI, values); + Cursor cursor = contentResolver.query(Words.CONTENT_URI, PROJECTION, + "word=? and ((locale IS NULL) or (locale=?))", + new String[] { word, mLocale }, null); + if (cursor != null && cursor.moveToFirst()) { + String locale = cursor.getString(cursor.getColumnIndex(Words.LOCALE)); + // If locale is null, we will not override the entry. + if (locale != null && locale.equals(mLocale.toString())) { + long id = cursor.getLong(cursor.getColumnIndex(Words._ID)); + Uri uri = Uri.withAppendedPath(Words.CONTENT_URI, Long.toString(id)); + // Update the entry with new frequency value. + contentResolver.update(uri, values, null, null); + } + } else { + // Insert new entry. + contentResolver.insert(Words.CONTENT_URI, values); + } } }.start(); diff --git a/native/src/defines.h b/native/src/defines.h index 52191beea..73394ce36 100644 --- a/native/src/defines.h +++ b/native/src/defines.h @@ -67,6 +67,7 @@ #define WORDS_WITH_MISSING_CHARACTER_DEMOTION_RATE 75 #define WORDS_WITH_MISSING_SPACE_CHARACTER_DEMOTION_RATE 80 #define WORDS_WITH_EXCESSIVE_CHARACTER_DEMOTION_RATE 75 +#define WORDS_WITH_EXCESSIVE_CHARACTER_OUT_OF_PROXIMITY_DEMOTION_RATE 75 #define WORDS_WITH_TRANSPOSED_CHARACTERS_DEMOTION_RATE 60 // This should be greater than or equal to MAX_WORD_LENGTH defined in BinaryDictionary.java @@ -75,7 +76,10 @@ #define MAX_DEPTH_MULTIPLIER 3 -#define MIN_SUGGEST_DEPTH 2 +// Minimum suggest depth for one word for all cases except for missing space suggestions. +#define MIN_SUGGEST_DEPTH 1 +#define MIN_USER_TYPED_LENGTH_FOR_MISSING_SPACE_SUGGESTION 3 +#define MIN_USER_TYPED_LENGTH_FOR_EXCESSIVE_CHARACTER_SUGGESTION 3 #define min(a,b) ((a)<(b)?(a):(b)) diff --git a/native/src/unigram_dictionary.cpp b/native/src/unigram_dictionary.cpp index 7ecf1c9c0..f679001cf 100644 --- a/native/src/unigram_dictionary.cpp +++ b/native/src/unigram_dictionary.cpp @@ -45,24 +45,25 @@ int UnigramDictionary::getSuggestions(int *codes, int codesSize, unsigned short int *frequencies, int *nextLetters, int nextLettersSize) { initSuggestions(codes, codesSize, outWords, frequencies); + if (DEBUG_DICT) assert(codesSize == mInputLength); + const int MAX_DEPTH = min(mInputLength * MAX_DEPTH_MULTIPLIER, MAX_WORD_LENGTH); - getSuggestionCandidates(codesSize, -1, -1, -1, nextLetters, nextLettersSize, MAX_DEPTH); + getSuggestionCandidates(-1, -1, -1, nextLetters, nextLettersSize, MAX_DEPTH); // Suggestion with missing character if (SUGGEST_WORDS_WITH_MISSING_CHARACTER) { for (int i = 0; i < codesSize; ++i) { if (DEBUG_DICT) LOGI("--- Suggest missing characters %d", i); - getSuggestionCandidates(codesSize, i, -1, -1, NULL, 0, MAX_DEPTH); + getSuggestionCandidates(i, -1, -1, NULL, 0, MAX_DEPTH); } } // Suggestion with excessive character - if (SUGGEST_WORDS_WITH_EXCESSIVE_CHARACTER && mInputLength > MIN_SUGGEST_DEPTH) { + if (SUGGEST_WORDS_WITH_EXCESSIVE_CHARACTER + && mInputLength >= MIN_USER_TYPED_LENGTH_FOR_EXCESSIVE_CHARACTER_SUGGESTION) { for (int i = 0; i < codesSize; ++i) { - if (existsAdjacentProximityChars(i, codesSize)) { - if (DEBUG_DICT) LOGI("--- Suggest excessive characters %d", i); - getSuggestionCandidates(codesSize, -1, i, -1, NULL, 0, MAX_DEPTH); - } + if (DEBUG_DICT) LOGI("--- Suggest excessive characters %d", i); + getSuggestionCandidates(-1, i, -1, NULL, 0, MAX_DEPTH); } } @@ -71,12 +72,13 @@ int UnigramDictionary::getSuggestions(int *codes, int codesSize, unsigned short if (SUGGEST_WORDS_WITH_TRANSPOSED_CHARACTERS) { for (int i = 0; i < codesSize; ++i) { if (DEBUG_DICT) LOGI("--- Suggest transposed characters %d", i); - getSuggestionCandidates(codesSize, -1, -1, i, NULL, 0, mInputLength - 1); + getSuggestionCandidates(-1, -1, i, NULL, 0, mInputLength - 1); } } // Suggestions with missing space - if (SUGGEST_WORDS_WITH_MISSING_SPACE_CHARACTER && mInputLength > MIN_SUGGEST_DEPTH) { + if (SUGGEST_WORDS_WITH_MISSING_SPACE_CHARACTER + && mInputLength >= MIN_USER_TYPED_LENGTH_FOR_MISSING_SPACE_SUGGESTION) { for (int i = 1; i < codesSize; ++i) { if (DEBUG_DICT) LOGI("--- Suggest missing space characters %d", i); getMissingSpaceWords(mInputLength, i); @@ -196,13 +198,15 @@ bool UnigramDictionary::sameAsTyped(unsigned short *word, int length) { static const char QUOTE = '\''; static const char SPACE = ' '; -void UnigramDictionary::getSuggestionCandidates(const int inputLength, const int skipPos, +void UnigramDictionary::getSuggestionCandidates(const int skipPos, const int excessivePos, const int transposedPos, int *nextLetters, const int nextLettersSize, const int maxDepth) { - if (DEBUG_DICT) LOGI("getSuggestionCandidates %d", maxDepth); - if (DEBUG_DICT) assert(transposedPos + 1 < inputLength); - if (DEBUG_DICT) assert(excessivePos < inputLength); - if (DEBUG_DICT) assert(missingPos < inputLength); + if (DEBUG_DICT) { + LOGI("getSuggestionCandidates %d", maxDepth); + assert(transposedPos + 1 < mInputLength); + assert(excessivePos < mInputLength); + assert(missingPos < mInputLength); + } int rootPosition = ROOT_POS; // Get the number of child of root, then increment the position int childCount = Dictionary::getCount(DICT, &rootPosition); @@ -321,41 +325,46 @@ void UnigramDictionary::getWordsRec(const int childrenCount, const int pos, cons } } -inline void UnigramDictionary::onTerminalWhenUserTypedLengthIsGreaterThanInputLength( - unsigned short *word, const int inputLength, const int depth, const int snr, - int *nextLetters, const int nextLettersSize, const int skipPos, const int excessivePos, - const int transposedPos, const int freq) { - int finalFreq = freq * snr; +inline int UnigramDictionary::calculateFinalFreq(const int inputIndex, const int snr, + const int skipPos, const int excessivePos, const int transposedPos, const int freq, + const bool sameLength) { // TODO: Demote by edit distance + int finalFreq = freq * snr; if (skipPos >= 0) finalFreq = finalFreq * WORDS_WITH_MISSING_CHARACTER_DEMOTION_RATE / 100; - if (excessivePos >= 0) finalFreq = finalFreq - * WORDS_WITH_EXCESSIVE_CHARACTER_DEMOTION_RATE / 100; if (transposedPos >= 0) finalFreq = finalFreq * WORDS_WITH_TRANSPOSED_CHARACTERS_DEMOTION_RATE / 100; + if (excessivePos >= 0) { + finalFreq = finalFreq * WORDS_WITH_EXCESSIVE_CHARACTER_DEMOTION_RATE / 100; + if (!existsAdjacentProximityChars(inputIndex, mInputLength)) { + finalFreq = finalFreq + * WORDS_WITH_EXCESSIVE_CHARACTER_OUT_OF_PROXIMITY_DEMOTION_RATE / 100; + } + } + if (sameLength && skipPos < 0) finalFreq *= FULL_WORD_MULTIPLIER; + return finalFreq; +} +inline void UnigramDictionary::onTerminalWhenUserTypedLengthIsGreaterThanInputLength( + unsigned short *word, const int inputIndex, const int depth, const int snr, + int *nextLetters, const int nextLettersSize, const int skipPos, const int excessivePos, + const int transposedPos, const int freq) { + const int finalFreq = calculateFinalFreq(inputIndex, snr, skipPos, excessivePos, transposedPos, + freq, false); if (depth >= MIN_SUGGEST_DEPTH) addWord(word, depth + 1, finalFreq); - if (depth >= inputLength && skipPos < 0) { + if (depth >= mInputLength && skipPos < 0) { registerNextLetter(mWord[mInputLength], nextLetters, nextLettersSize); } } inline void UnigramDictionary::onTerminalWhenUserTypedLengthIsSameAsInputLength( - unsigned short *word, const int depth, const int snr, const int skipPos, - const int excessivePos, const int transposedPos, const int freq, const int addedWeight) { - if (!sameAsTyped(word, depth + 1)) { - int finalFreq = freq * snr * addedWeight; - // TODO: Demote by edit distance - if (skipPos >= 0) finalFreq = finalFreq * WORDS_WITH_MISSING_CHARACTER_DEMOTION_RATE / 100; - if (excessivePos >= 0) finalFreq = finalFreq - * WORDS_WITH_EXCESSIVE_CHARACTER_DEMOTION_RATE / 100; - if (transposedPos >= 0) finalFreq = finalFreq - * WORDS_WITH_TRANSPOSED_CHARACTERS_DEMOTION_RATE / 100; - - // Proximity collection will promote a word of the same length as - // what user typed. - if (skipPos < 0) finalFreq *= FULL_WORD_MULTIPLIER; - if (depth >= MIN_SUGGEST_DEPTH) addWord(word, depth + 1, finalFreq); - } + unsigned short *word, const int inputIndex, const int depth, const int snr, + const int skipPos, const int excessivePos, const int transposedPos, const int freq, + const int addedWeight) { + if (sameAsTyped(word, depth + 1)) return; + const int finalFreq = calculateFinalFreq(inputIndex, snr * addedWeight, skipPos, + excessivePos, transposedPos, freq, true); + // Proximity collection will promote a word of the same length as what user typed. + if (depth >= MIN_SUGGEST_DEPTH) addWord(word, depth + 1, finalFreq); } inline bool UnigramDictionary::needsToSkipCurrentNode(const unsigned short c, @@ -437,7 +446,7 @@ inline bool UnigramDictionary::processCurrentNode(const int pos, const int depth if (traverseAllNodes || needsToSkipCurrentNode(c, inputIndex, skipPos, depth)) { mWord[depth] = c; if (traverseAllNodes && terminal) { - onTerminalWhenUserTypedLengthIsGreaterThanInputLength(mWord, mInputLength, depth, + onTerminalWhenUserTypedLengthIsGreaterThanInputLength(mWord, inputIndex, depth, snr, nextLetters, nextLettersSize, skipPos, excessivePos, transposedPos, freq); } if (!needsToTraverseChildrenNodes) return false; @@ -462,7 +471,7 @@ inline bool UnigramDictionary::processCurrentNode(const int pos, const int depth const int addedWeight = matchedProximityCharId == 0 ? TYPED_LETTER_MULTIPLIER : 1; const bool isSameAsUserTypedLength = mInputLength == inputIndex + 1; if (isSameAsUserTypedLength && terminal) { - onTerminalWhenUserTypedLengthIsSameAsInputLength(mWord, depth, snr, + onTerminalWhenUserTypedLengthIsSameAsInputLength(mWord, inputIndex, depth, snr, skipPos, excessivePos, transposedPos, freq, addedWeight); } if (!needsToTraverseChildrenNodes) return false; diff --git a/native/src/unigram_dictionary.h b/native/src/unigram_dictionary.h index abfdb8d87..445ff7a17 100644 --- a/native/src/unigram_dictionary.h +++ b/native/src/unigram_dictionary.h @@ -31,7 +31,7 @@ public: private: void initSuggestions(int *codes, int codesSize, unsigned short *outWords, int *frequencies); - void getSuggestionCandidates(const int inputLength, const int skipPos, const int excessivePos, + void getSuggestionCandidates(const int skipPos, const int excessivePos, const int transposedPos, int *nextLetters, const int nextLettersSize, const int maxDepth); void getVersionNumber(); @@ -52,13 +52,15 @@ private: const int excessivePos, const int transposedPos, int *nextLetters, const int nextLettersSize); void registerNextLetter(unsigned short c, int *nextLetters, int nextLettersSize); + int calculateFinalFreq(const int inputIndex, const int snr, const int skipPos, + const int excessivePos, const int transposedPos, const int freq, const bool sameLength); void onTerminalWhenUserTypedLengthIsGreaterThanInputLength(unsigned short *word, - const int mInputLength, const int depth, const int snr, int *nextLetters, + const int inputIndex, const int depth, const int snr, int *nextLetters, const int nextLettersSize, const int skipPos, const int excessivePos, const int transposedPos, const int freq); - void onTerminalWhenUserTypedLengthIsSameAsInputLength(unsigned short *word, const int depth, - const int snr, const int skipPos, const int excessivePos, const int transposedPos, - const int freq, const int addedWeight); + void onTerminalWhenUserTypedLengthIsSameAsInputLength(unsigned short *word, + const int inputIndex, const int depth, const int snr, const int skipPos, + const int excessivePos, const int transposedPos, const int freq, const int addedWeight); bool needsToSkipCurrentNode(const unsigned short c, const int inputIndex, const int skipPos, const int depth); int getMatchedProximityId(const int *currentChars, const unsigned short c, const int skipPos, |