diff options
Diffstat (limited to 'java')
6 files changed, 97 insertions, 23 deletions
diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java index 9a3ac674e..3c329bb5a 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java @@ -76,7 +76,7 @@ public final class BinaryDictionary extends Dictionary { private static final int FORMAT_WORD_PROPERTY_IS_NOT_A_WORD_INDEX = 0; private static final int FORMAT_WORD_PROPERTY_IS_POSSIBLY_OFFENSIVE_INDEX = 1; private static final int FORMAT_WORD_PROPERTY_HAS_NGRAMS_INDEX = 2; - private static final int FORMAT_WORD_PROPERTY_HAS_SHORTCUTS_INDEX = 3; // DEPRECATED + private static final int FORMAT_WORD_PROPERTY_HAS_SHORTCUTS_INDEX = 3; private static final int FORMAT_WORD_PROPERTY_IS_BEGINNING_OF_SENTENCE_INDEX = 4; // Format to get probability and historical info from native side via getWordPropertyNative(). @@ -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..732484c0c 100644 --- a/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java @@ -101,6 +101,8 @@ public class ContactsBinaryDictionary extends ExpandableBinaryDictionary } runGCIfRequiredLocked(true /* mindsBlockByGC */); addUnigramLocked(word, ContactsDictionaryConstants.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, ContactsDictionaryConstants.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..f9cc1c400 100644 --- a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java @@ -295,18 +295,21 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { * Adds unigram information of a word to the dictionary. May overwrite an existing entry. */ 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..1ed210377 100644 --- a/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java @@ -22,6 +22,7 @@ import android.database.ContentObserver; import android.database.Cursor; import android.database.sqlite.SQLiteException; import android.net.Uri; +import android.os.Build; import android.provider.UserDictionary.Words; import android.text.TextUtils; import android.util.Log; @@ -46,8 +47,19 @@ public class UserBinaryDictionary extends ExpandableBinaryDictionary { private static final String USER_DICTIONARY_ALL_LANGUAGES = ""; 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 +171,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 +219,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..388d57816 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, + 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,6 +70,7 @@ 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) { @@ -79,17 +84,21 @@ public final class WordProperty implements Comparable<WordProperty> { // 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 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[]> 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(); @@ -112,6 +121,14 @@ public final class WordProperty implements Comparable<WordProperty> { 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. diff --git a/java/src/com/android/inputmethod/latin/utils/CombinedFormatUtils.java b/java/src/com/android/inputmethod/latin/utils/CombinedFormatUtils.java index 5c0c4328f..476c13406 100644 --- a/java/src/com/android/inputmethod/latin/utils/CombinedFormatUtils.java +++ b/java/src/com/android/inputmethod/latin/utils/CombinedFormatUtils.java @@ -19,6 +19,7 @@ package com.android.inputmethod.latin.utils; import com.android.inputmethod.latin.makedict.DictionaryHeader; import com.android.inputmethod.latin.makedict.NgramProperty; import com.android.inputmethod.latin.makedict.ProbabilityInfo; +import com.android.inputmethod.latin.makedict.WeightedString; import com.android.inputmethod.latin.makedict.WordProperty; import java.util.HashMap; @@ -28,6 +29,7 @@ public class CombinedFormatUtils { public static final String BIGRAM_TAG = "bigram"; public static final String NGRAM_TAG = "ngram"; public static final String NGRAM_PREV_WORD_TAG = "prev_word"; + public static final String SHORTCUT_TAG = "shortcut"; public static final String PROBABILITY_TAG = "f"; public static final String HISTORICAL_INFO_TAG = "historicalInfo"; public static final String HISTORICAL_INFO_SEPARATOR = ":"; @@ -69,6 +71,14 @@ public class CombinedFormatUtils { builder.append("," + POSSIBLY_OFFENSIVE_TAG + "=" + TRUE_VALUE); } builder.append("\n"); + if (wordProperty.mHasShortcuts) { + for (final WeightedString shortcutTarget : wordProperty.mShortcutTargets) { + builder.append(" " + SHORTCUT_TAG + "=" + shortcutTarget.mWord); + builder.append(","); + builder.append(formatProbabilityInfo(shortcutTarget.mProbabilityInfo)); + builder.append("\n"); + } + } if (wordProperty.mHasNgrams) { for (final NgramProperty ngramProperty : wordProperty.mNgrams) { builder.append(" " + NGRAM_TAG + "=" + ngramProperty.mTargetWord.mWord); |
