diff options
6 files changed, 139 insertions, 21 deletions
diff --git a/java/src/com/android/inputmethod/dictionarypack/DictionarySettingsFragment.java b/java/src/com/android/inputmethod/dictionarypack/DictionarySettingsFragment.java index 7bbd041e7..d18639741 100644 --- a/java/src/com/android/inputmethod/dictionarypack/DictionarySettingsFragment.java +++ b/java/src/com/android/inputmethod/dictionarypack/DictionarySettingsFragment.java @@ -317,15 +317,19 @@ public final class DictionarySettingsFragment extends PreferenceFragment final WordListPreference pref; if (null != oldPreference && oldPreference.mVersion == version + && oldPreference.hasStatus(status) && oldPreference.mLocale.equals(locale)) { - // If the old preference has all the new attributes, reuse it. We test - // for version and locale because although attributes other than status - // need to be the same, others have been tested through the key of the - // map. Also, status may differ so we don't want to use #equals() here. + // If the old preference has all the new attributes, reuse it. Ideally, we + // should reuse the old pref even if its status is different and call + // setStatus here, but setStatus calls Preference#setSummary() which needs + // to be done on the UI thread and we're not on the UI thread here. We + // could do all this work on the UI thread, but in this case it's probably + // lighter to stay on a background thread and throw this old preference out. pref = oldPreference; - pref.setStatus(status); } else { // Otherwise, discard it and create a new one instead. + // TODO: when the status is different from the old one, we need to + // animate the old one out before animating the new one in. pref = new WordListPreference(activity, mDictionaryListInterfaceState, mClientId, wordlistId, version, locale, description, status, filesize); diff --git a/java/src/com/android/inputmethod/dictionarypack/WordListPreference.java b/java/src/com/android/inputmethod/dictionarypack/WordListPreference.java index ba1fce1a8..aea16af0d 100644 --- a/java/src/com/android/inputmethod/dictionarypack/WordListPreference.java +++ b/java/src/com/android/inputmethod/dictionarypack/WordListPreference.java @@ -98,6 +98,10 @@ public final class WordListPreference extends Preference { setSummary(getSummary(status)); } + public boolean hasStatus(final int status) { + return status == mStatus; + } + @Override public View onCreateView(final ViewGroup parent) { final View orphanedView = mInterfaceState.findFirstOrphanedView(); @@ -217,6 +221,7 @@ public final class WordListPreference extends Preference { progressBar.setIds(mClientId, mWordlistId); progressBar.setMax(mFilesize); final boolean showProgressBar = (MetadataDbHelper.STATUS_DOWNLOADING == mStatus); + setSummary(getSummary(mStatus)); status.setVisibility(showProgressBar ? View.INVISIBLE : View.VISIBLE); progressBar.setVisibility(showProgressBar ? View.VISIBLE : View.INVISIBLE); diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.cpp index 8172e70b6..bf38dffa5 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.cpp +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.cpp @@ -20,6 +20,7 @@ #include "defines.h" #include "suggest/core/dicnode/dic_node.h" #include "suggest/core/dicnode/dic_node_vector.h" +#include "suggest/core/dictionary/binary_dictionary_bigrams_iterator.h" #include "suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_reading_helper.h" #include "suggest/policyimpl/dictionary/structure/v2/patricia_trie_reading_utils.h" #include "suggest/policyimpl/dictionary/utils/probability_utils.h" @@ -303,4 +304,63 @@ int PatriciaTriePolicy::createAndGetLeavingChildNode(const DicNode *const dicNod return siblingPos; } +const WordProperty PatriciaTriePolicy::getWordProperty(const int *const codePoints, + const int codePointCount) const { + const int ptNodePos = getTerminalPtNodePositionOfWord(codePoints, codePointCount, + false /* forceLowerCaseSearch */); + if (ptNodePos == NOT_A_DICT_POS) { + AKLOGE("getWordProperty was called for invalid word."); + return WordProperty(); + } + const PtNodeParams ptNodeParams = mPtNodeReader.fetchNodeInfoInBufferFromPtNodePos(ptNodePos); + std::vector<int> codePointVector(ptNodeParams.getCodePoints(), + ptNodeParams.getCodePoints() + ptNodeParams.getCodePointCount()); + // Fetch bigram information. + std::vector<WordProperty::BigramProperty> bigrams; + const int bigramListPos = getBigramsPositionOfPtNode(ptNodePos); + int bigramWord1CodePoints[MAX_WORD_LENGTH]; + BinaryDictionaryBigramsIterator bigramsIt(getBigramsStructurePolicy(), bigramListPos); + while (bigramsIt.hasNext()) { + // Fetch the next bigram information and forward the iterator. + bigramsIt.next(); + // Skip the entry if the entry has been deleted. This never happens for ver2 dicts. + if (bigramsIt.getBigramPos() != NOT_A_DICT_POS) { + int word1Probability = NOT_A_PROBABILITY; + int word1CodePointCount = getCodePointsAndProbabilityAndReturnCodePointCount( + bigramsIt.getBigramPos(), MAX_WORD_LENGTH, bigramWord1CodePoints, + &word1Probability); + std::vector<int> word1(bigramWord1CodePoints, + bigramWord1CodePoints + word1CodePointCount); + bigrams.push_back(WordProperty::BigramProperty(&word1, bigramsIt.getProbability(), + NOT_A_TIMESTAMP /* timestamp */, 0 /* level */, 0 /* count */)); + } + } + // Fetch shortcut information. + std::vector<WordProperty::ShortcutProperty> shortcuts; + int shortcutPos = getShortcutPositionOfPtNode(ptNodePos); + if (shortcutPos != NOT_A_DICT_POS) { + int shortcutTargetCodePoints[MAX_WORD_LENGTH]; + ShortcutListReadingUtils::getShortcutListSizeAndForwardPointer(mDictRoot, &shortcutPos); + bool hasNext = true; + while (hasNext) { + const ShortcutListReadingUtils::ShortcutFlags shortcutFlags = + ShortcutListReadingUtils::getFlagsAndForwardPointer(mDictRoot, &shortcutPos); + hasNext = ShortcutListReadingUtils::hasNext(shortcutFlags); + const int shortcutTargetLength = ShortcutListReadingUtils::readShortcutTarget( + mDictRoot, MAX_WORD_LENGTH, shortcutTargetCodePoints, &shortcutPos); + std::vector<int> shortcutTarget(shortcutTargetCodePoints, + shortcutTargetCodePoints + shortcutTargetLength); + const int shortcutProbability = + ShortcutListReadingUtils::getProbabilityFromFlags(shortcutFlags); + shortcuts.push_back( + WordProperty::ShortcutProperty(&shortcutTarget, shortcutProbability)); + } + } + return WordProperty(&codePointVector, ptNodeParams.isNotAWord(), + ptNodeParams.isBlacklisted(), ptNodeParams.hasBigrams(), + ptNodeParams.hasShortcutTargets(), ptNodeParams.getProbability(), + NOT_A_TIMESTAMP /* timestamp */, 0 /* level */, 0 /* count */, + &bigrams, &shortcuts); +} + } // namespace latinime diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.h b/native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.h index 1ce7f85d4..da4be87ce 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.h +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.h @@ -128,10 +128,7 @@ class PatriciaTriePolicy : public DictionaryStructureWithBufferPolicy { } const WordProperty getWordProperty(const int *const codePoints, - const int codePointCount) const { - // getWordProperty is not supported. - return WordProperty(); - } + const int codePointCount) const; int getNextWordAndNextToken(const int token, int *const outCodePoints) { // getNextWordAndNextToken is not supported. diff --git a/tests/src/com/android/inputmethod/latin/makedict/BinaryDictDecoderEncoderTests.java b/tests/src/com/android/inputmethod/latin/makedict/BinaryDictDecoderEncoderTests.java index 141730de9..28388b4a0 100644 --- a/tests/src/com/android/inputmethod/latin/makedict/BinaryDictDecoderEncoderTests.java +++ b/tests/src/com/android/inputmethod/latin/makedict/BinaryDictDecoderEncoderTests.java @@ -39,6 +39,7 @@ import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Locale; import java.util.Map.Entry; import java.util.Random; import java.util.Set; @@ -596,4 +597,39 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase { Log.d(TAG, result); } } + + public void testVer2DictGetWordProperty() { + final FormatOptions formatOptions = BinaryDictUtils.VERSION2_OPTIONS; + final ArrayList<String> words = sWords; + final HashMap<String, List<String>> shortcuts = sShortcuts; + final String dictName = "testGetWordProperty"; + final String dictVersion = Long.toString(System.currentTimeMillis()); + final FusionDictionary dict = new FusionDictionary(new PtNodeArray(), + BinaryDictUtils.makeDictionaryOptions(dictName, dictVersion, formatOptions)); + addUnigrams(words.size(), dict, words, shortcuts); + addBigrams(dict, words, sEmptyBigrams); + final File file = BinaryDictUtils.getDictFile(dictName, dictVersion, formatOptions, + getContext().getCacheDir()); + file.delete(); + timeWritingDictToFile(file, dict, formatOptions); + final BinaryDictionary binaryDictionary = new BinaryDictionary(file.getAbsolutePath(), + 0 /* offset */, file.length(), true /* useFullEditDistance */, + Locale.ENGLISH, dictName, false /* isUpdatable */); + for (final String word : words) { + final WordProperty wordProperty = binaryDictionary.getWordProperty(word); + assertEquals(word, wordProperty.mWord); + assertEquals(UNIGRAM_FREQ, wordProperty.getProbability()); + if (shortcuts.containsKey(word)) { + assertEquals(shortcuts.get(word).size(), wordProperty.mShortcutTargets.size()); + final List<String> shortcutList = shortcuts.get(word); + assertTrue(wordProperty.mHasShortcuts); + for (final WeightedString shortcutTarget : wordProperty.mShortcutTargets) { + assertTrue(shortcutList.contains(shortcutTarget.mWord)); + assertEquals(UNIGRAM_FREQ, shortcutTarget.getProbability()); + shortcutList.remove(shortcutTarget.mWord); + } + assertTrue(shortcutList.isEmpty()); + } + } + } } diff --git a/tests/src/com/android/inputmethod/latin/settings/SpacingAndPunctuationsTests.java b/tests/src/com/android/inputmethod/latin/settings/SpacingAndPunctuationsTests.java index 09920bfe9..24af09484 100644 --- a/tests/src/com/android/inputmethod/latin/settings/SpacingAndPunctuationsTests.java +++ b/tests/src/com/android/inputmethod/latin/settings/SpacingAndPunctuationsTests.java @@ -373,37 +373,53 @@ public class SpacingAndPunctuationsTests extends AndroidTestCase { assertTrue(SWISS_GERMAN.mUsesGermanRules); } - private static final String[] PUNCTUATION_LABELS = { + private static final String[] PUNCTUATION_LABELS_LTR = { "!", "?", ",", ":", ";", "\"", "(", ")", "'", "-", "/", "@", "_" }; - private static final String[] PUNCTUATION_WORDS_LTR = PUNCTUATION_LABELS; - private static final String[] PUNCTUATION_WORDS_RTL = { + private static final String[] PUNCTUATION_WORDS_LTR = PUNCTUATION_LABELS_LTR; + private static final String[] PUNCTUATION_WORDS_HEBREW = { "!", "?", ",", ":", ";", "\"", ")", "(", "'", "-", "/", "@", "_" }; + // U+061F: "؟" ARABIC QUESTION MARK + // U+060C: "،" ARABIC COMMA + // U+061B: "؛" ARABIC SEMICOLON + private static final String[] PUNCTUATION_LABELS_ARABIC_PERSIAN = { + "!", "\u061F", "\u060C", ":", "\u061B", "\"", "(", ")", "'", "-", "/", "@", "_" + }; + private static final String[] PUNCTUATION_WORDS_ARABIC_PERSIAN = { + "!", "\u061F", "\u060C", ":", "\u061B", "\"", ")", "(", "'", "-", "/", "@", "_" + }; private static void testingStandardPunctuationSuggestions(final SpacingAndPunctuations sp, - final String[] punctuationWords) { + final String[] punctuationLabels, final String[] punctuationWords) { final SuggestedWords suggestedWords = sp.mSuggestPuncList; assertFalse("typedWordValid", suggestedWords.mTypedWordValid); assertFalse("willAutoCorrect", suggestedWords.mWillAutoCorrect); assertTrue("isPunctuationSuggestions", suggestedWords.isPunctuationSuggestions()); assertFalse("isObsoleteSuggestions", suggestedWords.mIsObsoleteSuggestions); assertFalse("isPrediction", suggestedWords.mIsPrediction); - assertEquals("size", PUNCTUATION_LABELS.length, suggestedWords.size()); + assertEquals("size", punctuationLabels.length, suggestedWords.size()); for (int index = 0; index < suggestedWords.size(); index++) { assertEquals("punctuation label at " + index, - PUNCTUATION_LABELS[index], suggestedWords.getLabel(index)); + punctuationLabels[index], suggestedWords.getLabel(index)); assertEquals("punctuation word at " + index, punctuationWords[index], suggestedWords.getWord(index)); } } + // TODO: Add tests for tablet as well public void testPunctuationSuggestions() { - testingStandardPunctuationSuggestions(ENGLISH, PUNCTUATION_WORDS_LTR); - testingStandardPunctuationSuggestions(FRENCH, PUNCTUATION_WORDS_LTR); - testingStandardPunctuationSuggestions(GERMAN, PUNCTUATION_WORDS_LTR); - testingStandardPunctuationSuggestions(ARABIC, PUNCTUATION_WORDS_RTL); - testingStandardPunctuationSuggestions(PERSIAN, PUNCTUATION_WORDS_RTL); - testingStandardPunctuationSuggestions(HEBREW, PUNCTUATION_WORDS_RTL); + testingStandardPunctuationSuggestions(ENGLISH, + PUNCTUATION_LABELS_LTR, PUNCTUATION_WORDS_LTR); + testingStandardPunctuationSuggestions(FRENCH, + PUNCTUATION_LABELS_LTR, PUNCTUATION_WORDS_LTR); + testingStandardPunctuationSuggestions(GERMAN, + PUNCTUATION_LABELS_LTR, PUNCTUATION_WORDS_LTR); + testingStandardPunctuationSuggestions(ARABIC, + PUNCTUATION_LABELS_ARABIC_PERSIAN, PUNCTUATION_WORDS_ARABIC_PERSIAN); + testingStandardPunctuationSuggestions(PERSIAN, + PUNCTUATION_LABELS_ARABIC_PERSIAN, PUNCTUATION_WORDS_ARABIC_PERSIAN); + testingStandardPunctuationSuggestions(HEBREW, + PUNCTUATION_LABELS_LTR, PUNCTUATION_WORDS_HEBREW); } } |