Merge "Add whitelist dictionary" into honeycomb-mr1
This commit is contained in:
commit
b55fcea6fc
7 changed files with 278 additions and 93 deletions
38
java/res/values/whitelist.xml
Normal file
38
java/res/values/whitelist.xml
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
/*
|
||||||
|
**
|
||||||
|
** Copyright 2011, The Android Open Source Project
|
||||||
|
**
|
||||||
|
** Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
** you may not use this file except in compliance with the License.
|
||||||
|
** You may obtain a copy of the License at
|
||||||
|
**
|
||||||
|
** http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
**
|
||||||
|
** Unless required by applicable law or agreed to in writing, software
|
||||||
|
** distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
** See the License for the specific language governing permissions and
|
||||||
|
** limitations under the License.
|
||||||
|
*/
|
||||||
|
-->
|
||||||
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
|
<!--
|
||||||
|
An entry of the whitelist word should be:
|
||||||
|
1. (int)frequency
|
||||||
|
2. (String)before
|
||||||
|
3. (String)after
|
||||||
|
-->
|
||||||
|
<string-array name="wordlist_whitelist">
|
||||||
|
|
||||||
|
<item>255</item>
|
||||||
|
<item>ill</item>
|
||||||
|
<item>I\'ll</item>
|
||||||
|
|
||||||
|
<item>255</item>
|
||||||
|
<item>thisd</item>
|
||||||
|
<item>this\'d</item>
|
||||||
|
|
||||||
|
</string-array>
|
||||||
|
</resources>
|
|
@ -16,10 +16,11 @@
|
||||||
|
|
||||||
package com.android.inputmethod.latin;
|
package com.android.inputmethod.latin;
|
||||||
|
|
||||||
|
import android.text.TextUtils;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Map;
|
||||||
|
|
||||||
public class AutoCorrection {
|
public class AutoCorrection {
|
||||||
private static final boolean DBG = LatinImeLogger.sDBG;
|
private static final boolean DBG = LatinImeLogger.sDBG;
|
||||||
|
@ -46,40 +47,73 @@ public class AutoCorrection {
|
||||||
return mNormalizedScore;
|
return mNormalizedScore;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateAutoCorrectionStatus(Collection<Dictionary> dictionaries,
|
public void updateAutoCorrectionStatus(Map<String, Dictionary> dictionaries,
|
||||||
WordComposer wordComposer, ArrayList<CharSequence> suggestions, int[] priorities,
|
WordComposer wordComposer, ArrayList<CharSequence> suggestions, int[] priorities,
|
||||||
CharSequence typedWord, double autoCorrectionThreshold, int correctionMode,
|
CharSequence typedWord, double autoCorrectionThreshold, int correctionMode,
|
||||||
CharSequence quickFixedWord) {
|
CharSequence quickFixedWord, CharSequence whitelistedWord) {
|
||||||
if (hasAutoCorrectionForTypedWord(
|
if (hasAutoCorrectionForWhitelistedWord(whitelistedWord)) {
|
||||||
|
mHasAutoCorrection = true;
|
||||||
|
mAutoCorrectionWord = whitelistedWord;
|
||||||
|
} else if (hasAutoCorrectionForTypedWord(
|
||||||
dictionaries, wordComposer, suggestions, typedWord, correctionMode)) {
|
dictionaries, wordComposer, suggestions, typedWord, correctionMode)) {
|
||||||
mHasAutoCorrection = true;
|
mHasAutoCorrection = true;
|
||||||
mAutoCorrectionWord = typedWord;
|
mAutoCorrectionWord = typedWord;
|
||||||
} else if (hasAutoCorrectForBinaryDictionary(wordComposer, suggestions, correctionMode,
|
|
||||||
priorities, typedWord, autoCorrectionThreshold)) {
|
|
||||||
mHasAutoCorrection = true;
|
|
||||||
mAutoCorrectionWord = suggestions.get(0);
|
|
||||||
} else if (hasAutoCorrectionForQuickFix(quickFixedWord)) {
|
} else if (hasAutoCorrectionForQuickFix(quickFixedWord)) {
|
||||||
mHasAutoCorrection = true;
|
mHasAutoCorrection = true;
|
||||||
mAutoCorrectionWord = quickFixedWord;
|
mAutoCorrectionWord = quickFixedWord;
|
||||||
|
} else if (hasAutoCorrectionForBinaryDictionary(wordComposer, suggestions, correctionMode,
|
||||||
|
priorities, typedWord, autoCorrectionThreshold)) {
|
||||||
|
mHasAutoCorrection = true;
|
||||||
|
mAutoCorrectionWord = suggestions.get(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean hasAutoCorrectionForTypedWord(Collection<Dictionary> dictionaries,
|
public static boolean isValidWord(
|
||||||
WordComposer wordComposer, ArrayList<CharSequence> suggestions, CharSequence typedWord,
|
Map<String, Dictionary> dictionaries, CharSequence word, boolean ignoreCase) {
|
||||||
int correctionMode) {
|
if (TextUtils.isEmpty(word)) {
|
||||||
boolean isValidWord = false;
|
return false;
|
||||||
for (final Dictionary dictionary : dictionaries) {
|
}
|
||||||
if (dictionary.isValidWord(typedWord)) {
|
final CharSequence lowerCasedWord = word.toString().toLowerCase();
|
||||||
isValidWord = true;
|
for (final String key : dictionaries.keySet()) {
|
||||||
break;
|
if (key.equals(Suggest.DICT_KEY_WHITELIST)) continue;
|
||||||
|
final Dictionary dictionary = dictionaries.get(key);
|
||||||
|
if (dictionary.isValidWord(word)
|
||||||
|
|| (ignoreCase && dictionary.isValidWord(lowerCasedWord))) {
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isValidWordForAutoCorrection(
|
||||||
|
Map<String, Dictionary> dictionaries, CharSequence word, boolean ignoreCase) {
|
||||||
|
final Dictionary whiteList = dictionaries.get(Suggest.DICT_KEY_WHITELIST);
|
||||||
|
// If "word" is in the whitelist dictionary, it should not be auto corrected.
|
||||||
|
if (whiteList != null && whiteList.isValidWord(word)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return isValidWord(dictionaries, word, ignoreCase);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean hasAutoCorrectionForWhitelistedWord(CharSequence whiteListedWord) {
|
||||||
|
return whiteListedWord != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasAutoCorrectionForTypedWord(Map<String, Dictionary> dictionaries,
|
||||||
|
WordComposer wordComposer, ArrayList<CharSequence> suggestions, CharSequence typedWord,
|
||||||
|
int correctionMode) {
|
||||||
|
if (TextUtils.isEmpty(typedWord)) return false;
|
||||||
|
boolean isValidWord = isValidWordForAutoCorrection(dictionaries, typedWord, false);
|
||||||
return wordComposer.size() > 1 && suggestions.size() > 0 && isValidWord
|
return wordComposer.size() > 1 && suggestions.size() > 0 && isValidWord
|
||||||
&& (correctionMode == Suggest.CORRECTION_FULL
|
&& (correctionMode == Suggest.CORRECTION_FULL
|
||||||
|| correctionMode == Suggest.CORRECTION_FULL_BIGRAM);
|
|| correctionMode == Suggest.CORRECTION_FULL_BIGRAM);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean hasAutoCorrectForBinaryDictionary(WordComposer wordComposer,
|
private static boolean hasAutoCorrectionForQuickFix(CharSequence quickFixedWord) {
|
||||||
|
return quickFixedWord != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasAutoCorrectionForBinaryDictionary(WordComposer wordComposer,
|
||||||
ArrayList<CharSequence> suggestions, int correctionMode, int[] priorities,
|
ArrayList<CharSequence> suggestions, int correctionMode, int[] priorities,
|
||||||
CharSequence typedWord, double autoCorrectionThreshold) {
|
CharSequence typedWord, double autoCorrectionThreshold) {
|
||||||
if (wordComposer.size() > 1 && (correctionMode == Suggest.CORRECTION_FULL
|
if (wordComposer.size() > 1 && (correctionMode == Suggest.CORRECTION_FULL
|
||||||
|
@ -106,7 +140,4 @@ public class AutoCorrection {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean hasAutoCorrectionForQuickFix(CharSequence quickFixedWord) {
|
|
||||||
return quickFixedWord != null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@ import android.provider.BaseColumns;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
|
|
@ -834,10 +834,10 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
|
||||||
public void onDisplayCompletions(CompletionInfo[] applicationSpecifiedCompletions) {
|
public void onDisplayCompletions(CompletionInfo[] applicationSpecifiedCompletions) {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Log.i(TAG, "Received completions:");
|
Log.i(TAG, "Received completions:");
|
||||||
final int count = (applicationSpecifiedCompletions != null)
|
if (applicationSpecifiedCompletions != null) {
|
||||||
? applicationSpecifiedCompletions.length : 0;
|
for (int i = 0; i < applicationSpecifiedCompletions.length; i++) {
|
||||||
for (int i = 0; i < count; i++) {
|
Log.i(TAG, " #" + i + ": " + applicationSpecifiedCompletions[i]);
|
||||||
Log.i(TAG, " #" + i + ": " + applicationSpecifiedCompletions[i]);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (mApplicationSpecifiedCompletionOn) {
|
if (mApplicationSpecifiedCompletionOn) {
|
||||||
|
@ -968,7 +968,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
|
||||||
}
|
}
|
||||||
mCommittedLength = mComposing.length();
|
mCommittedLength = mComposing.length();
|
||||||
TextEntryState.acceptedTyped(mComposing);
|
TextEntryState.acceptedTyped(mComposing);
|
||||||
addToDictionaries(mComposing, AutoDictionary.FREQUENCY_FOR_TYPED);
|
addToAutoAndUserBigramDictionaries(mComposing, AutoDictionary.FREQUENCY_FOR_TYPED);
|
||||||
}
|
}
|
||||||
updateSuggestions();
|
updateSuggestions();
|
||||||
}
|
}
|
||||||
|
@ -1537,10 +1537,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
|
||||||
|
|
||||||
boolean correctionAvailable = !mInputTypeNoAutoCorrect && mSuggest.hasAutoCorrection();
|
boolean correctionAvailable = !mInputTypeNoAutoCorrect && mSuggest.hasAutoCorrection();
|
||||||
final CharSequence typedWord = word.getTypedWord();
|
final CharSequence typedWord = word.getTypedWord();
|
||||||
// If we're in basic correct
|
// Here, we want to promote a whitelisted word if exists.
|
||||||
final boolean typedWordValid = mSuggest.isValidWord(typedWord) ||
|
final boolean typedWordValid = AutoCorrection.isValidWordForAutoCorrection(
|
||||||
(preferCapitalization()
|
mSuggest.getUnigramDictionaries(), typedWord, preferCapitalization());
|
||||||
&& mSuggest.isValidWord(typedWord.toString().toLowerCase()));
|
|
||||||
if (mCorrectionMode == Suggest.CORRECTION_FULL
|
if (mCorrectionMode == Suggest.CORRECTION_FULL
|
||||||
|| mCorrectionMode == Suggest.CORRECTION_FULL_BIGRAM) {
|
|| mCorrectionMode == Suggest.CORRECTION_FULL_BIGRAM) {
|
||||||
correctionAvailable |= typedWordValid;
|
correctionAvailable |= typedWordValid;
|
||||||
|
@ -1594,7 +1593,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
|
||||||
mJustAccepted = true;
|
mJustAccepted = true;
|
||||||
pickSuggestion(mBestWord);
|
pickSuggestion(mBestWord);
|
||||||
// Add the word to the auto dictionary if it's not a known word
|
// Add the word to the auto dictionary if it's not a known word
|
||||||
addToDictionaries(mBestWord, AutoDictionary.FREQUENCY_FOR_TYPED);
|
addToAutoAndUserBigramDictionaries(mBestWord, AutoDictionary.FREQUENCY_FOR_TYPED);
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1647,9 +1646,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
|
||||||
pickSuggestion(suggestion);
|
pickSuggestion(suggestion);
|
||||||
// Add the word to the auto dictionary if it's not a known word
|
// Add the word to the auto dictionary if it's not a known word
|
||||||
if (index == 0) {
|
if (index == 0) {
|
||||||
addToDictionaries(suggestion, AutoDictionary.FREQUENCY_FOR_PICKED);
|
addToAutoAndUserBigramDictionaries(suggestion, AutoDictionary.FREQUENCY_FOR_PICKED);
|
||||||
} else {
|
} else {
|
||||||
addToBigramDictionary(suggestion, 1);
|
addToOnlyBigramDictionary(suggestion, 1);
|
||||||
}
|
}
|
||||||
LatinImeLogger.logOnManualSuggestion(mComposing.toString(), suggestion.toString(),
|
LatinImeLogger.logOnManualSuggestion(mComposing.toString(), suggestion.toString(),
|
||||||
index, suggestions.mWords);
|
index, suggestions.mWords);
|
||||||
|
@ -1668,13 +1667,12 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
|
||||||
// and correction, so we shouldn't try to show the hint
|
// and correction, so we shouldn't try to show the hint
|
||||||
// We used to look at mCorrectionMode here, but showing the hint should have nothing
|
// We used to look at mCorrectionMode here, but showing the hint should have nothing
|
||||||
// to do with the autocorrection setting.
|
// to do with the autocorrection setting.
|
||||||
final boolean showingAddToDictionaryHint = index == 0 &&
|
final boolean showingAddToDictionaryHint = index == 0 && mSuggest != null
|
||||||
// Test for no dictionary:
|
// If there is no dictionary the hint should be shown.
|
||||||
((!mHasDictionary && null != mSuggest) ||
|
&& (!mHasDictionary
|
||||||
// Test for dictionary && word is inside:
|
// If "suggestion" is not in the dictionary, the hint should be shown.
|
||||||
(mHasDictionary && null != mSuggest
|
|| !AutoCorrection.isValidWord(
|
||||||
&& !mSuggest.isValidWord(suggestion)
|
mSuggest.getUnigramDictionaries(), suggestion, true));
|
||||||
&& !mSuggest.isValidWord(suggestion.toString().toLowerCase())));
|
|
||||||
|
|
||||||
if (!recorrecting) {
|
if (!recorrecting) {
|
||||||
// Fool the state watcher so that a subsequent backspace will not do a revert, unless
|
// Fool the state watcher so that a subsequent backspace will not do a revert, unless
|
||||||
|
@ -1726,6 +1724,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
|
||||||
// If we didn't find a match, search for result in typed word history
|
// If we didn't find a match, search for result in typed word history
|
||||||
WordComposer foundWord = null;
|
WordComposer foundWord = null;
|
||||||
WordAlternatives alternatives = null;
|
WordAlternatives alternatives = null;
|
||||||
|
// Search old suggestions to suggest re-corrected suggestions.
|
||||||
for (WordAlternatives entry : mWordHistory) {
|
for (WordAlternatives entry : mWordHistory) {
|
||||||
if (TextUtils.equals(entry.getChosenWord(), touching.mWord)) {
|
if (TextUtils.equals(entry.getChosenWord(), touching.mWord)) {
|
||||||
if (entry instanceof TypedWordAlternatives) {
|
if (entry instanceof TypedWordAlternatives) {
|
||||||
|
@ -1735,10 +1734,10 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// If we didn't find a match, at least suggest corrections.
|
// If we didn't find a match, at least suggest corrections as re-corrected suggestions.
|
||||||
if (foundWord == null
|
if (foundWord == null
|
||||||
&& (mSuggest.isValidWord(touching.mWord)
|
&& (AutoCorrection.isValidWord(
|
||||||
|| mSuggest.isValidWord(touching.mWord.toString().toLowerCase()))) {
|
mSuggest.getUnigramDictionaries(), touching.mWord, true))) {
|
||||||
foundWord = new WordComposer();
|
foundWord = new WordComposer();
|
||||||
for (int i = 0; i < touching.mWord.length(); i++) {
|
for (int i = 0; i < touching.mWord.length(); i++) {
|
||||||
foundWord.add(touching.mWord.charAt(i), new int[] {
|
foundWord.add(touching.mWord.charAt(i), new int[] {
|
||||||
|
@ -1801,21 +1800,22 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
|
||||||
setCandidatesViewShown(isCandidateStripVisible());
|
setCandidatesViewShown(isCandidateStripVisible());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addToDictionaries(CharSequence suggestion, int frequencyDelta) {
|
private void addToAutoAndUserBigramDictionaries(CharSequence suggestion, int frequencyDelta) {
|
||||||
checkAddToDictionary(suggestion, frequencyDelta, false);
|
checkAddToDictionary(suggestion, frequencyDelta, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addToBigramDictionary(CharSequence suggestion, int frequencyDelta) {
|
private void addToOnlyBigramDictionary(CharSequence suggestion, int frequencyDelta) {
|
||||||
checkAddToDictionary(suggestion, frequencyDelta, true);
|
checkAddToDictionary(suggestion, frequencyDelta, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds to the UserBigramDictionary and/or AutoDictionary
|
* Adds to the UserBigramDictionary and/or AutoDictionary
|
||||||
* @param addToBigramDictionary true if it should be added to bigram dictionary if possible
|
* @param selectedANotTypedWord true if it should be added to bigram dictionary if possible
|
||||||
*/
|
*/
|
||||||
private void checkAddToDictionary(CharSequence suggestion, int frequencyDelta,
|
private void checkAddToDictionary(CharSequence suggestion, int frequencyDelta,
|
||||||
boolean addToBigramDictionary) {
|
boolean selectedANotTypedWord) {
|
||||||
if (suggestion == null || suggestion.length() < 1) return;
|
if (suggestion == null || suggestion.length() < 1) return;
|
||||||
|
|
||||||
// Only auto-add to dictionary if auto-correct is ON. Otherwise we'll be
|
// Only auto-add to dictionary if auto-correct is ON. Otherwise we'll be
|
||||||
// adding words in situations where the user or application really didn't
|
// adding words in situations where the user or application really didn't
|
||||||
// want corrections enabled or learned.
|
// want corrections enabled or learned.
|
||||||
|
@ -1823,9 +1823,14 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
|
||||||
|| mCorrectionMode == Suggest.CORRECTION_FULL_BIGRAM)) {
|
|| mCorrectionMode == Suggest.CORRECTION_FULL_BIGRAM)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!addToBigramDictionary && mAutoDictionary.isValidWord(suggestion)
|
|
||||||
|| (!mSuggest.isValidWord(suggestion.toString())
|
final boolean selectedATypedWordAndItsInAutoDic =
|
||||||
&& !mSuggest.isValidWord(suggestion.toString().toLowerCase()))) {
|
!selectedANotTypedWord && mAutoDictionary.isValidWord(suggestion);
|
||||||
|
final boolean isValidWord = AutoCorrection.isValidWord(
|
||||||
|
mSuggest.getUnigramDictionaries(), suggestion, true);
|
||||||
|
final boolean needsToAddToAutoDictionary = selectedATypedWordAndItsInAutoDic
|
||||||
|
|| !isValidWord;
|
||||||
|
if (needsToAddToAutoDictionary) {
|
||||||
mAutoDictionary.addWord(suggestion.toString(), frequencyDelta);
|
mAutoDictionary.addWord(suggestion.toString(), frequencyDelta);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -67,6 +67,13 @@ public class Suggest implements Dictionary.WordCallback {
|
||||||
// If you add a type of dictionary, increment DIC_TYPE_LAST_ID
|
// If you add a type of dictionary, increment DIC_TYPE_LAST_ID
|
||||||
public static final int DIC_TYPE_LAST_ID = 4;
|
public static final int DIC_TYPE_LAST_ID = 4;
|
||||||
|
|
||||||
|
public static final String DICT_KEY_MAIN = "main";
|
||||||
|
public static final String DICT_KEY_CONTACTS = "contacts";
|
||||||
|
public static final String DICT_KEY_AUTO = "auto";
|
||||||
|
public static final String DICT_KEY_USER = "user";
|
||||||
|
public static final String DICT_KEY_USER_BIGRAM = "user_bigram";
|
||||||
|
public static final String DICT_KEY_WHITELIST ="whitelist";
|
||||||
|
|
||||||
static final int LARGE_DICTIONARY_THRESHOLD = 200 * 1000;
|
static final int LARGE_DICTIONARY_THRESHOLD = 200 * 1000;
|
||||||
|
|
||||||
private static final boolean DBG = LatinImeLogger.sDBG;
|
private static final boolean DBG = LatinImeLogger.sDBG;
|
||||||
|
@ -74,11 +81,7 @@ public class Suggest implements Dictionary.WordCallback {
|
||||||
private AutoCorrection mAutoCorrection;
|
private AutoCorrection mAutoCorrection;
|
||||||
|
|
||||||
private BinaryDictionary mMainDict;
|
private BinaryDictionary mMainDict;
|
||||||
private static final String DICT_KEY_MAIN = "main";
|
private WhitelistDictionary mWhiteListDictionary;
|
||||||
private static final String DICT_KEY_CONTACTS = "contacts";
|
|
||||||
private static final String DICT_KEY_AUTO = "auto";
|
|
||||||
private static final String DICT_KEY_USER = "user";
|
|
||||||
private static final String DICT_KEY_USER_BIGRAM = "user_bigram";
|
|
||||||
private final Map<String, Dictionary> mUnigramDictionaries = new HashMap<String, Dictionary>();
|
private final Map<String, Dictionary> mUnigramDictionaries = new HashMap<String, Dictionary>();
|
||||||
private final Map<String, Dictionary> mBigramDictionaries = new HashMap<String, Dictionary>();
|
private final Map<String, Dictionary> mBigramDictionaries = new HashMap<String, Dictionary>();
|
||||||
|
|
||||||
|
@ -104,19 +107,23 @@ public class Suggest implements Dictionary.WordCallback {
|
||||||
private int mCorrectionMode = CORRECTION_BASIC;
|
private int mCorrectionMode = CORRECTION_BASIC;
|
||||||
|
|
||||||
public Suggest(Context context, int dictionaryResId) {
|
public Suggest(Context context, int dictionaryResId) {
|
||||||
init(BinaryDictionary.initDictionary(context, dictionaryResId, DIC_MAIN));
|
init(context, BinaryDictionary.initDictionary(context, dictionaryResId, DIC_MAIN));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* package for test */ Suggest(File dictionary, long startOffset, long length) {
|
/* package for test */ Suggest(File dictionary, long startOffset, long length) {
|
||||||
init(BinaryDictionary.initDictionary(dictionary, startOffset, length, DIC_MAIN));
|
init(null, BinaryDictionary.initDictionary(dictionary, startOffset, length, DIC_MAIN));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void init(BinaryDictionary mainDict) {
|
private void init(Context context, BinaryDictionary mainDict) {
|
||||||
if (mainDict != null) {
|
if (mainDict != null) {
|
||||||
mMainDict = mainDict;
|
mMainDict = mainDict;
|
||||||
mUnigramDictionaries.put(DICT_KEY_MAIN, mainDict);
|
mUnigramDictionaries.put(DICT_KEY_MAIN, mainDict);
|
||||||
mBigramDictionaries.put(DICT_KEY_MAIN, mainDict);
|
mBigramDictionaries.put(DICT_KEY_MAIN, mainDict);
|
||||||
}
|
}
|
||||||
|
mWhiteListDictionary = WhitelistDictionary.init(context);
|
||||||
|
if (mWhiteListDictionary != null) {
|
||||||
|
mUnigramDictionaries.put(DICT_KEY_WHITELIST, mWhiteListDictionary);
|
||||||
|
}
|
||||||
mAutoCorrection = new AutoCorrection();
|
mAutoCorrection = new AutoCorrection();
|
||||||
initPool();
|
initPool();
|
||||||
}
|
}
|
||||||
|
@ -144,6 +151,10 @@ public class Suggest implements Dictionary.WordCallback {
|
||||||
return mMainDict != null && mMainDict.getSize() > LARGE_DICTIONARY_THRESHOLD;
|
return mMainDict != null && mMainDict.getSize() > LARGE_DICTIONARY_THRESHOLD;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Map<String, Dictionary> getUnigramDictionaries() {
|
||||||
|
return mUnigramDictionaries;
|
||||||
|
}
|
||||||
|
|
||||||
public int getApproxMaxWordLength() {
|
public int getApproxMaxWordLength() {
|
||||||
return APPROX_MAX_WORD_LENGTH;
|
return APPROX_MAX_WORD_LENGTH;
|
||||||
}
|
}
|
||||||
|
@ -218,6 +229,25 @@ public class Suggest implements Dictionary.WordCallback {
|
||||||
return getSuggestedWordBuilder(view, wordComposer, prevWordForBigram).build();
|
return getSuggestedWordBuilder(view, wordComposer, prevWordForBigram).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private CharSequence capitalizeWord(boolean all, boolean first, CharSequence word) {
|
||||||
|
if (TextUtils.isEmpty(word) || !(all || first)) return word;
|
||||||
|
final int wordLength = word.length();
|
||||||
|
final int poolSize = mStringPool.size();
|
||||||
|
final StringBuilder sb =
|
||||||
|
poolSize > 0 ? (StringBuilder) mStringPool.remove(poolSize - 1)
|
||||||
|
: new StringBuilder(getApproxMaxWordLength());
|
||||||
|
sb.setLength(0);
|
||||||
|
if (all) {
|
||||||
|
sb.append(word.toString().toUpperCase());
|
||||||
|
} else if (first) {
|
||||||
|
sb.append(Character.toUpperCase(word.charAt(0)));
|
||||||
|
if (wordLength > 1) {
|
||||||
|
sb.append(word.subSequence(1, wordLength));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sb;
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: cleanup dictionaries looking up and suggestions building with SuggestedWords.Builder
|
// TODO: cleanup dictionaries looking up and suggestions building with SuggestedWords.Builder
|
||||||
public SuggestedWords.Builder getSuggestedWordBuilder(View view, WordComposer wordComposer,
|
public SuggestedWords.Builder getSuggestedWordBuilder(View view, WordComposer wordComposer,
|
||||||
CharSequence prevWordForBigram) {
|
CharSequence prevWordForBigram) {
|
||||||
|
@ -277,8 +307,8 @@ public class Suggest implements Dictionary.WordCallback {
|
||||||
} else if (wordComposer.size() > 1) {
|
} else if (wordComposer.size() > 1) {
|
||||||
// At second character typed, search the unigrams (scores being affected by bigrams)
|
// At second character typed, search the unigrams (scores being affected by bigrams)
|
||||||
for (final String key : mUnigramDictionaries.keySet()) {
|
for (final String key : mUnigramDictionaries.keySet()) {
|
||||||
// Skip AutoDictionary to lookup
|
// Skip AutoDictionary and WhitelistDictionary to lookup
|
||||||
if (key.equals(DICT_KEY_AUTO))
|
if (key.equals(DICT_KEY_AUTO) || key.equals(DICT_KEY_WHITELIST))
|
||||||
continue;
|
continue;
|
||||||
final Dictionary dictionary = mUnigramDictionaries.get(key);
|
final Dictionary dictionary = mUnigramDictionaries.get(key);
|
||||||
dictionary.getWords(wordComposer, this);
|
dictionary.getWords(wordComposer, this);
|
||||||
|
@ -290,28 +320,12 @@ public class Suggest implements Dictionary.WordCallback {
|
||||||
// Apply quick fix only for the typed word.
|
// Apply quick fix only for the typed word.
|
||||||
if (mQuickFixesEnabled) {
|
if (mQuickFixesEnabled) {
|
||||||
final String lowerCaseTypedWord = typedWordString.toLowerCase();
|
final String lowerCaseTypedWord = typedWordString.toLowerCase();
|
||||||
CharSequence tempAutoText =
|
CharSequence tempAutoText = capitalizeWord(
|
||||||
AutoText.get(lowerCaseTypedWord, 0, lowerCaseTypedWord.length(), view);
|
mIsAllUpperCase, mIsFirstCharCapitalized, AutoText.get(
|
||||||
|
lowerCaseTypedWord, 0, lowerCaseTypedWord.length(), view));
|
||||||
|
// TODO: cleanup canAdd
|
||||||
// Is there an AutoText (also known as Quick Fixes) correction?
|
// Is there an AutoText (also known as Quick Fixes) correction?
|
||||||
// Capitalize as needed
|
// Capitalize as needed
|
||||||
if (!TextUtils.isEmpty(tempAutoText)
|
|
||||||
&& (mIsAllUpperCase || mIsFirstCharCapitalized)) {
|
|
||||||
final int tempAutoTextLength = tempAutoText.length();
|
|
||||||
final int poolSize = mStringPool.size();
|
|
||||||
final StringBuilder sb =
|
|
||||||
poolSize > 0 ? (StringBuilder) mStringPool.remove(poolSize - 1)
|
|
||||||
: new StringBuilder(getApproxMaxWordLength());
|
|
||||||
sb.setLength(0);
|
|
||||||
if (mIsAllUpperCase) {
|
|
||||||
sb.append(tempAutoText.toString().toUpperCase());
|
|
||||||
} else if (mIsFirstCharCapitalized) {
|
|
||||||
sb.append(Character.toUpperCase(tempAutoText.charAt(0)));
|
|
||||||
if (tempAutoTextLength > 1) {
|
|
||||||
sb.append(tempAutoText.subSequence(1, tempAutoTextLength));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
tempAutoText = sb.toString();
|
|
||||||
}
|
|
||||||
boolean canAdd = tempAutoText != null;
|
boolean canAdd = tempAutoText != null;
|
||||||
// Is that correction already the current prediction (or original word)?
|
// Is that correction already the current prediction (or original word)?
|
||||||
canAdd &= !TextUtils.equals(tempAutoText, typedWord);
|
canAdd &= !TextUtils.equals(tempAutoText, typedWord);
|
||||||
|
@ -328,14 +342,21 @@ public class Suggest implements Dictionary.WordCallback {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mAutoCorrection.updateAutoCorrectionStatus(mUnigramDictionaries.values(), wordComposer,
|
CharSequence whitelistedWord = capitalizeWord(mIsAllUpperCase, mIsFirstCharCapitalized,
|
||||||
|
mWhiteListDictionary.getWhiteListedWord(typedWordString));
|
||||||
|
|
||||||
|
mAutoCorrection.updateAutoCorrectionStatus(mUnigramDictionaries, wordComposer,
|
||||||
mSuggestions, mPriorities, typedWord, mAutoCorrectionThreshold, mCorrectionMode,
|
mSuggestions, mPriorities, typedWord, mAutoCorrectionThreshold, mCorrectionMode,
|
||||||
autoText);
|
autoText, whitelistedWord);
|
||||||
|
|
||||||
if (autoText != null) {
|
if (autoText != null) {
|
||||||
mSuggestions.add(0, autoText);
|
mSuggestions.add(0, autoText);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (whitelistedWord != null) {
|
||||||
|
mSuggestions.add(0, whitelistedWord);
|
||||||
|
}
|
||||||
|
|
||||||
if (typedWord != null) {
|
if (typedWord != null) {
|
||||||
mSuggestions.add(0, typedWordString);
|
mSuggestions.add(0, typedWordString);
|
||||||
}
|
}
|
||||||
|
@ -516,17 +537,6 @@ public class Suggest implements Dictionary.WordCallback {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isValidWord(final CharSequence word) {
|
|
||||||
if (word == null || word.length() == 0 || mMainDict == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
for (final Dictionary dictionary : mUnigramDictionaries.values()) {
|
|
||||||
if (dictionary.isValidWord(word))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void collectGarbage(ArrayList<CharSequence> suggestions, int prefMaxSuggestions) {
|
private void collectGarbage(ArrayList<CharSequence> suggestions, int prefMaxSuggestions) {
|
||||||
int poolSize = mStringPool.size();
|
int poolSize = mStringPool.size();
|
||||||
int garbageSize = suggestions.size();
|
int garbageSize = suggestions.size();
|
||||||
|
|
|
@ -0,0 +1,99 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2011 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
|
* use this file except in compliance with the License. You may obtain a copy of
|
||||||
|
* the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations under
|
||||||
|
* the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.inputmethod.latin;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.util.Pair;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
public class WhitelistDictionary extends Dictionary {
|
||||||
|
|
||||||
|
private static final boolean DBG = LatinImeLogger.sDBG;
|
||||||
|
private static final String TAG = WhitelistDictionary.class.getSimpleName();
|
||||||
|
|
||||||
|
private final HashMap<String, Pair<Integer, String>> mWhitelistWords =
|
||||||
|
new HashMap<String, Pair<Integer, String>>();
|
||||||
|
|
||||||
|
private static final WhitelistDictionary sInstance = new WhitelistDictionary();
|
||||||
|
|
||||||
|
private WhitelistDictionary() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static WhitelistDictionary init(Context context) {
|
||||||
|
synchronized (sInstance) {
|
||||||
|
if (context != null) {
|
||||||
|
sInstance.initWordlist(
|
||||||
|
context.getResources().getStringArray(R.array.wordlist_whitelist));
|
||||||
|
} else {
|
||||||
|
sInstance.mWhitelistWords.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initWordlist(String[] wordlist) {
|
||||||
|
mWhitelistWords.clear();
|
||||||
|
final int N = wordlist.length;
|
||||||
|
if (N % 3 != 0) {
|
||||||
|
if (DBG) {
|
||||||
|
Log.d(TAG, "The number of the whitelist is invalid.");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
for (int i = 0; i < N; i += 3) {
|
||||||
|
final int score = Integer.valueOf(wordlist[i]);
|
||||||
|
final String before = wordlist[i + 1];
|
||||||
|
final String after = wordlist[i + 2];
|
||||||
|
if (before != null && after != null) {
|
||||||
|
mWhitelistWords.put(
|
||||||
|
before.toLowerCase(), new Pair<Integer, String>(score, after));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
if (DBG) {
|
||||||
|
Log.d(TAG, "The score of the word is invalid.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getWhiteListedWord(String before) {
|
||||||
|
if (before == null) return null;
|
||||||
|
final String lowerCaseBefore = before.toLowerCase();
|
||||||
|
if(mWhitelistWords.containsKey(lowerCaseBefore)) {
|
||||||
|
if (DBG) {
|
||||||
|
Log.d(TAG, "--- found whiteListedWord: " + lowerCaseBefore);
|
||||||
|
}
|
||||||
|
return mWhitelistWords.get(lowerCaseBefore).second;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not used for WhitelistDictionary. We use getWhitelistedWord() in Suggest.java instead
|
||||||
|
@Override
|
||||||
|
public void getWords(WordComposer composer, WordCallback callback) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isValidWord(CharSequence word) {
|
||||||
|
if (TextUtils.isEmpty(word)) return false;
|
||||||
|
return !TextUtils.isEmpty(getWhiteListedWord(word.toString()));
|
||||||
|
}
|
||||||
|
}
|
|
@ -89,7 +89,8 @@ public class SuggestHelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isValidWord(CharSequence typed) {
|
public boolean isValidWord(CharSequence typed) {
|
||||||
return mSuggest.isValidWord(typed);
|
return AutoCorrection.isValidWordForAutoCorrection(mSuggest.getUnigramDictionaries(),
|
||||||
|
typed, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: This may be slow, but is OK for test so far.
|
// TODO: This may be slow, but is OK for test so far.
|
||||||
|
|
Loading…
Reference in a new issue