summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDan Yu <dyu@cyngn.com>2016-08-03 16:50:47 -0700
committerGerrit Code Review <gerrit@cyanogenmod.org>2016-08-17 15:21:56 -0700
commit877f8b481a6c6452a3894df14ec527c21d8e2d8c (patch)
tree464f403d68a2e48db6c32a985dd284c8cefeab46
parentfa3518fb978580a4eb15b1e9f746afa812ba47df (diff)
downloadandroid_packages_inputmethods_LatinIME-877f8b481a6c6452a3894df14ec527c21d8e2d8c.tar.gz
android_packages_inputmethods_LatinIME-877f8b481a6c6452a3894df14ec527c21d8e2d8c.tar.bz2
android_packages_inputmethods_LatinIME-877f8b481a6c6452a3894df14ec527c21d8e2d8c.zip
LatinIME: add shortcut functionality
Add shortcut functionality by creating property method/property calls to accommodate. CYNGNOS-3129 Change-Id: I19d07846a405fd3e53dddb2c6db43cb350435c54
-rw-r--r--java/src/com/android/inputmethod/latin/BinaryDictionary.java19
-rw-r--r--java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java10
-rw-r--r--java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java12
-rw-r--r--java/src/com/android/inputmethod/latin/UserBinaryDictionary.java43
-rw-r--r--java/src/com/android/inputmethod/latin/makedict/WordProperty.java50
5 files changed, 100 insertions, 34 deletions
diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java
index 9a3ac674e..4171b05ba 100644
--- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java
@@ -412,9 +412,11 @@ public final class BinaryDictionary extends Dictionary {
outFlags[FORMAT_WORD_PROPERTY_IS_NOT_A_WORD_INDEX],
outFlags[FORMAT_WORD_PROPERTY_IS_POSSIBLY_OFFENSIVE_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,
outNgramPrevWordsArray, outNgramPrevWordIsBeginningOfSentenceArray,
- outNgramTargets, outNgramProbabilityInfo);
+ outNgramTargets, outNgramProbabilityInfo, outShortcutTargets,
+ outShortcutProbabilities);
}
public static class GetNextWordPropertyResult {
@@ -442,16 +444,19 @@ public final class BinaryDictionary extends Dictionary {
}
// Add a unigram entry to binary dictionary with unigram attributes in native code.
- public boolean addUnigramEntry(
- final String word, final int probability, final boolean isBeginningOfSentence,
- final boolean isNotAWord, final boolean isPossiblyOffensive, final int timestamp) {
+ public boolean addUnigramEntry(final String word, final int probability,
+ final String shortcutTarget, final int shortcutProbability,
+ final boolean isBeginningOfSentence, final boolean isNotAWord,
+ final boolean isPossiblyOffensive, final int timestamp) {
if (word == null || (word.isEmpty() && !isBeginningOfSentence)) {
return false;
}
final int[] codePoints = StringUtils.toCodePointArray(word);
- if (!addUnigramEntryNative(mNativeDict, codePoints, probability,
- null /* shortcutTargetCodePoints */, 0 /* shortcutProbability */,
- isBeginningOfSentence, isNotAWord, isPossiblyOffensive, timestamp)) {
+ final int[] shortcutTargetCodePoints = (shortcutTarget != null) ?
+ StringUtils.toCodePointArray(shortcutTarget) : null;
+ if (!addUnigramEntryNative(mNativeDict, codePoints, probability, shortcutTargetCodePoints,
+ shortcutProbability, isBeginningOfSentence, isNotAWord, isPossiblyOffensive,
+ timestamp)) {
return false;
}
mHasUpdated = true;
diff --git a/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java
index dbd639fe8..f38c44ca3 100644
--- a/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java
@@ -41,6 +41,8 @@ public class ContactsBinaryDictionary extends ExpandableBinaryDictionary
private static final String TAG = ContactsBinaryDictionary.class.getSimpleName();
private static final String NAME = "contacts";
+ private static final int FREQUENCY_FOR_CONTACTS = 40;
+
private static final boolean DEBUG = false;
private static final boolean DEBUG_DUMP = false;
@@ -100,8 +102,8 @@ public class ContactsBinaryDictionary extends ExpandableBinaryDictionary
Log.d(TAG, "loadAccountVocabulary: " + word);
}
runGCIfRequiredLocked(true /* mindsBlockByGC */);
- addUnigramLocked(word, ContactsDictionaryConstants.FREQUENCY_FOR_CONTACTS,
- false /* isNotAWord */, false /* isPossiblyOffensive */,
+ addUnigramLocked(word, FREQUENCY_FOR_CONTACTS, null /* shortcut */,
+ 0 /* shortcutFreq */, false /* isNotAWord */, false /* isPossiblyOffensive */,
BinaryDictionary.NOT_A_VALID_TIMESTAMP);
}
}
@@ -151,8 +153,8 @@ public class ContactsBinaryDictionary extends ExpandableBinaryDictionary
Log.d(TAG, "addName " + name + ", " + word + ", " + ngramContext);
}
runGCIfRequiredLocked(true /* mindsBlockByGC */);
- addUnigramLocked(word,
- ContactsDictionaryConstants.FREQUENCY_FOR_CONTACTS, false /* isNotAWord */,
+ addUnigramLocked(word, FREQUENCY_FOR_CONTACTS,
+ null /* shortcut */, 0 /* shortcutFreq */, false /* isNotAWord */,
false /* isPossiblyOffensive */,
BinaryDictionary.NOT_A_VALID_TIMESTAMP);
if (ngramContext.isValid() && mUseFirstLastBigrams) {
diff --git a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
index 907095746..9ec283ec7 100644
--- a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
@@ -294,19 +294,23 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
/**
* Adds unigram information of a word to the dictionary. May overwrite an existing entry.
*/
+ // Add a unigram entry to binary dictionary with unigram attributes in native code.
public void addUnigramEntry(final String word, final int frequency,
- final boolean isNotAWord, final boolean isPossiblyOffensive, final int timestamp) {
+ final String shortcutTarget, final int shortcutFreq, final boolean isNotAWord,
+ final boolean isPossiblyOffensive, final int timestamp) {
updateDictionaryWithWriteLock(new Runnable() {
@Override
public void run() {
- addUnigramLocked(word, frequency, isNotAWord, isPossiblyOffensive, timestamp);
+ addUnigramLocked(word, frequency, shortcutTarget, shortcutFreq,
+ isNotAWord, isPossiblyOffensive, timestamp);
}
});
}
protected void addUnigramLocked(final String word, final int frequency,
- final boolean isNotAWord, final boolean isPossiblyOffensive, final int timestamp) {
- if (!mBinaryDictionary.addUnigramEntry(word, frequency,
+ final String shortcutTarget, final int shortcutFreq, final boolean isNotAWord,
+ final boolean isPossiblyOffensive, final int timestamp) {
+ if (!mBinaryDictionary.addUnigramEntry(word, frequency, shortcutTarget, shortcutFreq,
false /* isBeginningOfSentence */, isNotAWord, isPossiblyOffensive, timestamp)) {
Log.e(TAG, "Cannot add unigram entry. word: " + word);
}
diff --git a/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java b/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java
index fe24ccfc2..bd0e75f6b 100644
--- a/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java
@@ -25,6 +25,7 @@ import android.net.Uri;
import android.provider.UserDictionary.Words;
import android.text.TextUtils;
import android.util.Log;
+import android.os.Build;
import com.android.inputmethod.annotations.ExternallyReferenced;
import com.android.inputmethod.latin.utils.SubtypeLocaleUtils;
@@ -47,7 +48,19 @@ public class UserBinaryDictionary extends ExpandableBinaryDictionary {
private static final int HISTORICAL_DEFAULT_USER_DICTIONARY_FREQUENCY = 250;
private static final int LATINIME_DEFAULT_USER_DICTIONARY_FREQUENCY = 160;
- private static final String[] PROJECTION_QUERY = new String[] {Words.WORD, Words.FREQUENCY};
+ // Shortcut frequency is 0~15, with 15 = whitelist. We don't want user dictionary entries
+ // to auto-correct, so we set this to the highest frequency that won't, i.e. 14.
+ private static final int USER_DICT_SHORTCUT_FREQUENCY = 14;
+
+ private static final String[] PROJECTION_QUERY_WITH_SHORTCUT = new String[] {
+ Words.WORD,
+ Words.SHORTCUT,
+ Words.FREQUENCY,
+ };
+ private static final String[] PROJECTION_QUERY_WITHOUT_SHORTCUT = new String[] {
+ Words.WORD,
+ Words.FREQUENCY,
+ };
private static final String NAME = "userunigram";
@@ -159,7 +172,20 @@ public class UserBinaryDictionary extends ExpandableBinaryDictionary {
requestArguments = localeElements;
}
final String requestString = request.toString();
- addWordsFromProjectionLocked(PROJECTION_QUERY, requestString, requestArguments);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
+ try {
+ addWordsFromProjectionLocked(PROJECTION_QUERY_WITH_SHORTCUT, requestString,
+ requestArguments);
+ } catch (IllegalArgumentException e) {
+ // This may happen on some non-compliant devices where the declared API is JB+ but
+ // the SHORTCUT column is not present for some reason.
+ addWordsFromProjectionLocked(PROJECTION_QUERY_WITHOUT_SHORTCUT, requestString,
+ requestArguments);
+ }
+ } else {
+ addWordsFromProjectionLocked(PROJECTION_QUERY_WITHOUT_SHORTCUT, requestString,
+ requestArguments);
+ }
}
private void addWordsFromProjectionLocked(final String[] query, String request,
@@ -194,20 +220,31 @@ public class UserBinaryDictionary extends ExpandableBinaryDictionary {
}
private void addWordsLocked(final Cursor cursor) {
+ final boolean hasShortcutColumn = Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN;
if (cursor == null) return;
if (cursor.moveToFirst()) {
final int indexWord = cursor.getColumnIndex(Words.WORD);
+ final int indexShortcut = hasShortcutColumn ? cursor.getColumnIndex(Words.SHORTCUT) : 0;
final int indexFrequency = cursor.getColumnIndex(Words.FREQUENCY);
while (!cursor.isAfterLast()) {
final String word = cursor.getString(indexWord);
+ final String shortcut = hasShortcutColumn ? cursor.getString(indexShortcut) : null;
final int frequency = cursor.getInt(indexFrequency);
final int adjustedFrequency = scaleFrequencyFromDefaultToLatinIme(frequency);
// Safeguard against adding really long words.
if (word.length() <= MAX_WORD_LENGTH) {
runGCIfRequiredLocked(true /* mindsBlockByGC */);
- addUnigramLocked(word, adjustedFrequency, false /* isNotAWord */,
+ addUnigramLocked(word, adjustedFrequency, null /* shortcutTarget */,
+ 0 /* shortcutFreq */, false /* isNotAWord */,
false /* isPossiblyOffensive */,
BinaryDictionary.NOT_A_VALID_TIMESTAMP);
+ if (null != shortcut && shortcut.length() <= MAX_WORD_LENGTH) {
+ runGCIfRequiredLocked(true /* mindsBlockByGC */);
+ addUnigramLocked(shortcut, adjustedFrequency, word,
+ USER_DICT_SHORTCUT_FREQUENCY, true /* isNotAWord */,
+ false /* isPossiblyOffensive */,
+ BinaryDictionary.NOT_A_VALID_TIMESTAMP);
+ }
}
cursor.moveToNext();
}
diff --git a/java/src/com/android/inputmethod/latin/makedict/WordProperty.java b/java/src/com/android/inputmethod/latin/makedict/WordProperty.java
index 264e75710..ac03dffba 100644
--- a/java/src/com/android/inputmethod/latin/makedict/WordProperty.java
+++ b/java/src/com/android/inputmethod/latin/makedict/WordProperty.java
@@ -37,11 +37,13 @@ import javax.annotation.Nullable;
public final class WordProperty implements Comparable<WordProperty> {
public final String mWord;
public final ProbabilityInfo mProbabilityInfo;
+ public final ArrayList<WeightedString> mShortcutTargets;
public final ArrayList<NgramProperty> mNgrams;
// TODO: Support mIsBeginningOfSentence.
public final boolean mIsBeginningOfSentence;
public final boolean mIsNotAWord;
public final boolean mIsPossiblyOffensive;
+ public final boolean mHasShortcuts;
public final boolean mHasNgrams;
private int mHashCode = 0;
@@ -49,10 +51,12 @@ public final class WordProperty implements Comparable<WordProperty> {
// TODO: Support n-gram.
@UsedForTesting
public WordProperty(final String word, final ProbabilityInfo probabilityInfo,
- @Nullable final ArrayList<WeightedString> bigrams,
- final boolean isNotAWord, final boolean isPossiblyOffensive) {
+ final ArrayList<WeightedString> shortcutTargets,
+ @Nullable final ArrayList<WeightedString> bigrams,
+ final boolean isNotAWord, final boolean isPossiblyOffensive) {
mWord = word;
mProbabilityInfo = probabilityInfo;
+ mShortcutTargets = shortcutTargets;
if (null == bigrams) {
mNgrams = null;
} else {
@@ -66,30 +70,35 @@ public final class WordProperty implements Comparable<WordProperty> {
mIsNotAWord = isNotAWord;
mIsPossiblyOffensive = isPossiblyOffensive;
mHasNgrams = bigrams != null && !bigrams.isEmpty();
+ mHasShortcuts = shortcutTargets != null && !shortcutTargets.isEmpty();
}
private static ProbabilityInfo createProbabilityInfoFromArray(final int[] probabilityInfo) {
- return new ProbabilityInfo(
- probabilityInfo[BinaryDictionary.FORMAT_WORD_PROPERTY_PROBABILITY_INDEX],
- probabilityInfo[BinaryDictionary.FORMAT_WORD_PROPERTY_TIMESTAMP_INDEX],
- probabilityInfo[BinaryDictionary.FORMAT_WORD_PROPERTY_LEVEL_INDEX],
- probabilityInfo[BinaryDictionary.FORMAT_WORD_PROPERTY_COUNT_INDEX]);
+ return new ProbabilityInfo(
+ probabilityInfo[BinaryDictionary.FORMAT_WORD_PROPERTY_PROBABILITY_INDEX],
+ probabilityInfo[BinaryDictionary.FORMAT_WORD_PROPERTY_TIMESTAMP_INDEX],
+ probabilityInfo[BinaryDictionary.FORMAT_WORD_PROPERTY_LEVEL_INDEX],
+ probabilityInfo[BinaryDictionary.FORMAT_WORD_PROPERTY_COUNT_INDEX]);
}
// Construct word property using information from native code.
// This represents invalid word when the probability is BinaryDictionary.NOT_A_PROBABILITY.
public WordProperty(final int[] codePoints, final boolean isNotAWord,
- final boolean isPossiblyOffensive, final boolean hasBigram,
- final boolean isBeginningOfSentence, final int[] probabilityInfo,
- final ArrayList<int[][]> ngramPrevWordsArray,
- final ArrayList<boolean[]> ngramPrevWordIsBeginningOfSentenceArray,
- final ArrayList<int[]> ngramTargets, final ArrayList<int[]> ngramProbabilityInfo) {
+ final boolean isPossiblyOffensive, final boolean hasBigram, final boolean hasShortcuts,
+ final boolean isBeginningOfSentence, final int[] probabilityInfo,
+ final ArrayList<int[][]> ngramPrevWordsArray,
+ final ArrayList<boolean[]> ngramPrevWordIsBeginningOfSentenceArray,
+ final ArrayList<int[]> ngramTargets, final ArrayList<int[]> ngramProbabilityInfo,
+ final ArrayList<int[]> shortcutTargets,
+ final ArrayList<Integer> shortcutProbabilities) {
mWord = StringUtils.getStringFromNullTerminatedCodePointArray(codePoints);
mProbabilityInfo = createProbabilityInfoFromArray(probabilityInfo);
+ mShortcutTargets = new ArrayList<>();
final ArrayList<NgramProperty> ngrams = new ArrayList<>();
mIsBeginningOfSentence = isBeginningOfSentence;
mIsNotAWord = isNotAWord;
mIsPossiblyOffensive = isPossiblyOffensive;
+ mHasShortcuts = hasShortcuts;
mHasNgrams = hasBigram;
final int relatedNgramCount = ngramTargets.size();
@@ -106,12 +115,20 @@ public final class WordProperty implements Comparable<WordProperty> {
wordInfoArray[j] = isBeginningOfSentenceArray[j]
? WordInfo.BEGINNING_OF_SENTENCE_WORD_INFO
: new WordInfo(StringUtils.getStringFromNullTerminatedCodePointArray(
- prevWords[j]));
+ prevWords[j]));
}
final NgramContext ngramContext = new NgramContext(wordInfoArray);
ngrams.add(new NgramProperty(ngramTarget, ngramContext));
}
mNgrams = ngrams.isEmpty() ? null : ngrams;
+
+ final int shortcutTargetCount = shortcutTargets.size();
+ for (int i = 0; i < shortcutTargetCount; i++) {
+ final String shortcutTargetString =
+ StringUtils.getStringFromNullTerminatedCodePointArray(shortcutTargets.get(i));
+ mShortcutTargets.add(
+ new WeightedString(shortcutTargetString, shortcutProbabilities.get(i)));
+ }
}
// TODO: Remove
@@ -137,6 +154,7 @@ public final class WordProperty implements Comparable<WordProperty> {
return Arrays.hashCode(new Object[] {
word.mWord,
word.mProbabilityInfo,
+ word.mShortcutTargets,
word.mNgrams,
word.mIsNotAWord,
word.mIsPossiblyOffensive
@@ -167,10 +185,10 @@ public final class WordProperty implements Comparable<WordProperty> {
if (o == this) return true;
if (!(o instanceof WordProperty)) return false;
WordProperty w = (WordProperty)o;
- return mProbabilityInfo.equals(w.mProbabilityInfo)
- && mWord.equals(w.mWord) && equals(mNgrams, w.mNgrams)
+ return mProbabilityInfo.equals(w.mProbabilityInfo) && mWord.equals(w.mWord)
+ && mShortcutTargets.equals(w.mShortcutTargets) && equals(mNgrams, w.mNgrams)
&& mIsNotAWord == w.mIsNotAWord && mIsPossiblyOffensive == w.mIsPossiblyOffensive
- && mHasNgrams == w.mHasNgrams;
+ && mHasNgrams == w.mHasNgrams && mHasShortcuts && w.mHasNgrams;
}
// TDOO: Have a utility method like java.util.Objects.equals.