Read and use user dictionary shortcuts.
Bug: 4646172 Change-Id: I51002c73d5bad1a698110c5cda02253348be8eedmain
parent
a9aeb6f3cc
commit
19ad9bf145
|
@ -149,7 +149,8 @@ public class ContactsDictionary extends ExpandableDictionary {
|
|||
// capitalization of i.
|
||||
final int wordLen = word.length();
|
||||
if (wordLen < maxWordLength && wordLen > 1) {
|
||||
super.addWord(word, FREQUENCY_FOR_CONTACTS);
|
||||
super.addWord(word, null /* shortcut */,
|
||||
FREQUENCY_FOR_CONTACTS);
|
||||
if (!TextUtils.isEmpty(prevWord)) {
|
||||
super.setBigram(prevWord, word,
|
||||
FREQUENCY_FOR_CONTACTS_BIGRAM);
|
||||
|
|
|
@ -23,11 +23,6 @@ import com.android.inputmethod.keyboard.ProximityInfo;
|
|||
* strokes.
|
||||
*/
|
||||
public abstract class Dictionary {
|
||||
/**
|
||||
* Whether or not to replicate the typed word in the suggested list, even if it's valid.
|
||||
*/
|
||||
protected static final boolean INCLUDE_TYPED_WORD_IF_VALID = false;
|
||||
|
||||
/**
|
||||
* The weight to give to a word if it's length is the same as the number of typed characters.
|
||||
*/
|
||||
|
|
|
@ -22,6 +22,7 @@ import com.android.inputmethod.keyboard.KeyDetector;
|
|||
import com.android.inputmethod.keyboard.Keyboard;
|
||||
import com.android.inputmethod.keyboard.ProximityInfo;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
|
||||
/**
|
||||
|
@ -53,6 +54,8 @@ public class ExpandableDictionary extends Dictionary {
|
|||
boolean mTerminal;
|
||||
Node mParent;
|
||||
NodeArray mChildren;
|
||||
ArrayList<char[]> mShortcutTargets;
|
||||
boolean mShortcutOnly;
|
||||
LinkedList<NextWord> mNGrams; // Supports ngram
|
||||
}
|
||||
|
||||
|
@ -150,15 +153,15 @@ public class ExpandableDictionary extends Dictionary {
|
|||
return BinaryDictionary.MAX_WORD_LENGTH;
|
||||
}
|
||||
|
||||
public void addWord(String word, int frequency) {
|
||||
public void addWord(final String word, final String shortcutTarget, final int frequency) {
|
||||
if (word.length() >= BinaryDictionary.MAX_WORD_LENGTH) {
|
||||
return;
|
||||
}
|
||||
addWordRec(mRoots, word, 0, frequency, null);
|
||||
addWordRec(mRoots, word, 0, shortcutTarget, frequency, null);
|
||||
}
|
||||
|
||||
private void addWordRec(NodeArray children, final String word, final int depth,
|
||||
final int frequency, Node parentNode) {
|
||||
final String shortcutTarget, final int frequency, Node parentNode) {
|
||||
final int wordLength = word.length();
|
||||
if (wordLength <= depth) return;
|
||||
final char c = word.charAt(depth);
|
||||
|
@ -172,15 +175,25 @@ public class ExpandableDictionary extends Dictionary {
|
|||
break;
|
||||
}
|
||||
}
|
||||
final boolean isShortcutOnly = (null != shortcutTarget);
|
||||
if (childNode == null) {
|
||||
childNode = new Node();
|
||||
childNode.mCode = c;
|
||||
childNode.mParent = parentNode;
|
||||
childNode.mShortcutOnly = isShortcutOnly;
|
||||
children.add(childNode);
|
||||
}
|
||||
if (wordLength == depth + 1) {
|
||||
// Terminate this word
|
||||
childNode.mTerminal = true;
|
||||
if (isShortcutOnly) {
|
||||
if (null == childNode.mShortcutTargets) {
|
||||
childNode.mShortcutTargets = new ArrayList<char[]>();
|
||||
}
|
||||
childNode.mShortcutTargets.add(shortcutTarget.toCharArray());
|
||||
} else {
|
||||
childNode.mShortcutOnly = false;
|
||||
}
|
||||
childNode.mFrequency = Math.max(frequency, childNode.mFrequency);
|
||||
if (childNode.mFrequency > 255) childNode.mFrequency = 255;
|
||||
return;
|
||||
|
@ -188,7 +201,7 @@ public class ExpandableDictionary extends Dictionary {
|
|||
if (childNode.mChildren == null) {
|
||||
childNode.mChildren = new NodeArray();
|
||||
}
|
||||
addWordRec(childNode.mChildren, word, depth + 1, frequency, childNode);
|
||||
addWordRec(childNode.mChildren, word, depth + 1, shortcutTarget, frequency, childNode);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -239,7 +252,13 @@ public class ExpandableDictionary extends Dictionary {
|
|||
if (mRequiresReload) startDictionaryLoadingTaskLocked();
|
||||
if (mUpdatingDictionary) return false;
|
||||
}
|
||||
return getWordFrequency(word) > -1;
|
||||
final Node node = searchNode(mRoots, word, 0, word.length());
|
||||
// If node is null, we didn't find the word, so it's not valid.
|
||||
// If node.mShortcutOnly is true, then it exists as a shortcut but not as a word,
|
||||
// so that means it's not a valid word.
|
||||
// If node.mShortcutOnly is false, then it exists as a word (it may also exist as
|
||||
// a shortcut, but this does not matter), so it's a valid word.
|
||||
return (node == null) ? false : !node.mShortcutOnly;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -247,7 +266,7 @@ public class ExpandableDictionary extends Dictionary {
|
|||
*/
|
||||
protected int getWordFrequency(CharSequence word) {
|
||||
// Case-sensitive search
|
||||
Node node = searchNode(mRoots, word, 0, word.length());
|
||||
final Node node = searchNode(mRoots, word, 0, word.length());
|
||||
return (node == null) ? -1 : node.mFrequency;
|
||||
}
|
||||
|
||||
|
@ -261,6 +280,35 @@ public class ExpandableDictionary extends Dictionary {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to add a word and its shortcuts.
|
||||
*
|
||||
* @param node the terminal node
|
||||
* @param word the word to insert, as an array of code points
|
||||
* @param depth the depth of the node in the tree
|
||||
* @param finalFreq the frequency for this word
|
||||
* @return whether there is still space for more words. {@see Dictionary.WordCallback#addWord}.
|
||||
*/
|
||||
private boolean addWordAndShortcutsFromNode(final Node node, final char[] word, final int depth,
|
||||
final int finalFreq, final WordCallback callback) {
|
||||
if (finalFreq > 0 && !node.mShortcutOnly) {
|
||||
if (!callback.addWord(word, 0, depth + 1, finalFreq, mDicTypeId, Dictionary.UNIGRAM)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (null != node.mShortcutTargets) {
|
||||
final int length = node.mShortcutTargets.size();
|
||||
for (int shortcutIndex = 0; shortcutIndex < length; ++shortcutIndex) {
|
||||
final char[] shortcut = node.mShortcutTargets.get(shortcutIndex);
|
||||
if (!callback.addWord(shortcut, 0, shortcut.length, finalFreq, mDicTypeId,
|
||||
Dictionary.UNIGRAM)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively traverse the tree for words that match the input. Input consists of
|
||||
* a list of arrays. Each item in the list is one input character position. An input
|
||||
|
@ -313,8 +361,8 @@ public class ExpandableDictionary extends Dictionary {
|
|||
} else {
|
||||
finalFreq = computeSkippedWordFinalFreq(freq, snr, mInputLength);
|
||||
}
|
||||
if (!callback.addWord(word, 0, depth + 1, finalFreq, mDicTypeId,
|
||||
Dictionary.UNIGRAM)) {
|
||||
if (!addWordAndShortcutsFromNode(node, word, depth, finalFreq, callback)) {
|
||||
// No space left in the queue, bail out
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -344,18 +392,18 @@ public class ExpandableDictionary extends Dictionary {
|
|||
|
||||
if (codeSize == inputIndex + 1) {
|
||||
if (terminal) {
|
||||
if (INCLUDE_TYPED_WORD_IF_VALID
|
||||
|| !same(word, depth + 1, codes.getTypedWord())) {
|
||||
final int finalFreq;
|
||||
if (skipPos < 0) {
|
||||
finalFreq = freq * snr * addedAttenuation
|
||||
* FULL_WORD_SCORE_MULTIPLIER;
|
||||
} else {
|
||||
finalFreq = computeSkippedWordFinalFreq(freq,
|
||||
snr * addedAttenuation, mInputLength);
|
||||
}
|
||||
callback.addWord(word, 0, depth + 1, finalFreq, mDicTypeId,
|
||||
Dictionary.UNIGRAM);
|
||||
final int finalFreq;
|
||||
if (skipPos < 0) {
|
||||
finalFreq = freq * snr * addedAttenuation
|
||||
* FULL_WORD_SCORE_MULTIPLIER;
|
||||
} else {
|
||||
finalFreq = computeSkippedWordFinalFreq(freq,
|
||||
snr * addedAttenuation, mInputLength);
|
||||
}
|
||||
if (!addWordAndShortcutsFromNode(node, word, depth, finalFreq,
|
||||
callback)) {
|
||||
// No space left in the queue, bail out
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (children != null) {
|
||||
|
|
|
@ -1120,7 +1120,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
|
|||
|
||||
@Override
|
||||
public boolean addWordToDictionary(String word) {
|
||||
mUserDictionary.addWord(word, 128);
|
||||
mUserDictionary.addWordToUserDictionary(word, 128);
|
||||
// Suggestion strip should be updated after the operation of adding word to the
|
||||
// user dictionary
|
||||
mHandler.postUpdateSuggestions();
|
||||
|
|
|
@ -42,6 +42,6 @@ public class SynchronouslyLoadedUserDictionary extends UserDictionary {
|
|||
@Override
|
||||
public synchronized boolean isValidWord(CharSequence word) {
|
||||
blockingReloadDictionaryIfRequired();
|
||||
return getWordFrequency(word) > -1;
|
||||
return super.isValidWord(word);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,8 +31,11 @@ import java.util.Arrays;
|
|||
|
||||
public class UserDictionary extends ExpandableDictionary {
|
||||
|
||||
// TODO: use Words.SHORTCUT when it's public in the SDK
|
||||
final static String SHORTCUT = "shortcut";
|
||||
private static final String[] PROJECTION_QUERY = {
|
||||
Words.WORD,
|
||||
SHORTCUT,
|
||||
Words.FREQUENCY,
|
||||
};
|
||||
|
||||
|
@ -149,15 +152,18 @@ public class UserDictionary extends ExpandableDictionary {
|
|||
}
|
||||
|
||||
/**
|
||||
* Adds a word to the dictionary and makes it persistent.
|
||||
* Adds a word to the user dictionary and makes it persistent.
|
||||
*
|
||||
* This will call upon the system interface to do the actual work through the intent
|
||||
* readied by the system to this effect.
|
||||
*
|
||||
* @param word the word to add. If the word is capitalized, then the dictionary will
|
||||
* recognize it as a capitalized word when searched.
|
||||
* @param frequency the frequency of occurrence of the word. A frequency of 255 is considered
|
||||
* the highest.
|
||||
* @TODO use a higher or float range for frequency
|
||||
*/
|
||||
@Override
|
||||
public synchronized void addWord(final String word, final int frequency) {
|
||||
public synchronized void addWordToUserDictionary(final String word, final int frequency) {
|
||||
// Force load the dictionary here synchronously
|
||||
if (getRequiresReload()) loadDictionaryAsync();
|
||||
// TODO: do something for the UI. With the following, any sufficiently long word will
|
||||
|
@ -191,14 +197,19 @@ public class UserDictionary extends ExpandableDictionary {
|
|||
final int maxWordLength = getMaxWordLength();
|
||||
if (cursor.moveToFirst()) {
|
||||
final int indexWord = cursor.getColumnIndex(Words.WORD);
|
||||
final int indexShortcut = cursor.getColumnIndex(SHORTCUT);
|
||||
final int indexFrequency = cursor.getColumnIndex(Words.FREQUENCY);
|
||||
while (!cursor.isAfterLast()) {
|
||||
String word = cursor.getString(indexWord);
|
||||
String shortcut = cursor.getString(indexShortcut);
|
||||
int frequency = cursor.getInt(indexFrequency);
|
||||
// Safeguard against adding really long words. Stack may overflow due
|
||||
// to recursion
|
||||
if (word.length() < maxWordLength) {
|
||||
super.addWord(word, frequency);
|
||||
super.addWord(word, null, frequency);
|
||||
}
|
||||
if (null != shortcut && shortcut.length() < maxWordLength) {
|
||||
super.addWord(shortcut, word, frequency);
|
||||
}
|
||||
cursor.moveToNext();
|
||||
}
|
||||
|
|
|
@ -176,7 +176,7 @@ public class UserHistoryDictionary extends ExpandableDictionary {
|
|||
* The second word may not be null (a NullPointerException would be thrown).
|
||||
*/
|
||||
public int addToUserHistory(final String word1, String word2) {
|
||||
super.addWord(word2, FREQUENCY_FOR_TYPED);
|
||||
super.addWord(word2, null /* shortcut */, FREQUENCY_FOR_TYPED);
|
||||
// Do not insert a word as a bigram of itself
|
||||
if (word2.equals(word1)) {
|
||||
return 0;
|
||||
|
@ -246,7 +246,7 @@ public class UserHistoryDictionary extends ExpandableDictionary {
|
|||
// Safeguard against adding really long words. Stack may overflow due
|
||||
// to recursive lookup
|
||||
if (null == word1) {
|
||||
super.addWord(word2, frequency);
|
||||
super.addWord(word2, null /* shortcut */, frequency);
|
||||
} else if (word1.length() < BinaryDictionary.MAX_WORD_LENGTH
|
||||
&& word2.length() < BinaryDictionary.MAX_WORD_LENGTH) {
|
||||
super.setBigram(word1, word2, frequency);
|
||||
|
|
|
@ -66,7 +66,7 @@ public class WhitelistDictionary extends ExpandableDictionary {
|
|||
if (before != null && after != null) {
|
||||
mWhitelistWords.put(
|
||||
before.toLowerCase(), new Pair<Integer, String>(score, after));
|
||||
addWord(after, score);
|
||||
addWord(after, null /* shortcut */, score);
|
||||
}
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
|
|
Loading…
Reference in New Issue