diff options
67 files changed, 790 insertions, 1928 deletions
diff --git a/java/res/xml/method.xml b/java/res/xml/method.xml index 78e771fda..c8e3c198e 100644 --- a/java/res/xml/method.xml +++ b/java/res/xml/method.xml @@ -24,54 +24,54 @@ keyboard_locale: script_name/keyboard_layout_set af: Afrikaans/qwerty ar: Arabic/arabic - (az: Azerbaijani/qwerty) # disabled temporarily. waiting for string resources. - be_BY: Belarusian/east_slavic + (az_AZ: Azerbaijani (Azerbaijan)/qwerty) # disabled temporarily. waiting for string resources. + be_BY: Belarusian (Belarus)/east_slavic bg: Bulgarian/bulgarian bg: Bulgarian/bulgarian_bds ca: Catalan/spanish cs: Czech/qwertz da: Danish/nordic de: German/qwertz - de_CH: German Switzerland/swiss + de_CH: German (Switzerland)/swiss el: Greek/greek - en_US: English United States/qwerty - en_GB: English Great Britain/qwerty + en_US: English (United States)/qwerty + en_GB: English (Great Britain)/qwerty eo: Esperanto/spanish es: Spanish/spanish - es_US: Spanish United States/spanish - (es_419: Spanish Latin America/qwerty) - et_EE: Estonian/nordic + es_US: Spanish (United States)/spanish + (es_419: Spanish (Latin America)/qwerty) + et_EE: Estonian (Estonia)/nordic fa: Persian/arabic fi: Finnish/nordic fr: French/azerty - fr_CA: French Canada/qwerty - fr_CH: French Switzerland/swiss + fr_CA: French (Canada)/qwerty + fr_CH: French (Switzerland)/swiss hi: Hindi/hindi hr: Croatian/qwertz hu: Hungarian/qwertz - hy_AM: Armenian Phonetic/armenian_phonetic + hy_AM: Armenian (Armenia) Phonetic/armenian_phonetic in: Indonesian/qwerty # "id" is official language code of Indonesian. is: Icelandic/qwerty it: Italian/qwerty iw: Hebrew/hebrew # "he" is official language code of Hebrew. - ka_GE: Georgian/georgian + ka_GE: Georgian (Georgia)/georgian (kk: Kazakh/east_slavic) # disabled temporarily. waiting for string resources. - km_KH: Khmer/khmer + km_KH: Khmer (Cambodia)/khmer ky: Kyrgyz/east_slavic - lo_LA: Lao/lao + lo_LA: Lao (Laos)/lao lt: Lithuanian/qwerty lv: Latvian/qwerty mk: Macedonian/south_slavic - mn_MN: Mongolian/mongolian - ms_MY: Malay/qwerty + mn_MN: Mongolian (Mongolia)/mongolian + ms_MY: Malay (Malaysia)/qwerty nb: Norwegian Bokmål/nordic - (ne: Nepali Romanized/nepali_romanized) # disabled temporarily - (ne: Nepali Traditional/nepali_traditional) # disabled temporarily + (ne_NP: Nepali (Nepal) Romanized/nepali_romanized) # disabled temporarily + (ne_NP: Nepali (Nepal) Traditional/nepali_traditional) # disabled temporarily nl: Dutch/qwerty - nl_BE: Dutch Belgium/azerty + nl_BE: Dutch (Belgium)/azerty pl: Polish/qwerty - pt_BR: Portuguese Brazil/qwerty - pt_PT: Portuguese Portugal/qwerty + pt_BR: Portuguese (Brazil)/qwerty + pt_PT: Portuguese (Portugal)/qwerty ro: Romanian/qwerty ru: Russian/east_slavic sk: Slovak/qwerty @@ -135,7 +135,7 @@ <subtype android:icon="@drawable/ic_ime_switcher_dark" android:label="@string/subtype_generic" android:subtypeId="0x70b0f974" - android:imeSubtypeLocale="az" + android:imeSubtypeLocale="az_AZ" android:imeSubtypeMode="keyboard" android:imeSubtypeExtraValue="KeyboardLayoutSet=qwerty,AsciiCapable,EmojiCapable" android:isAsciiCapable="true" @@ -455,7 +455,7 @@ <subtype android:icon="@drawable/ic_ime_switcher_dark" android:label="@string/subtype_generic" android:subtypeId="0xd80a4cee" - android:imeSubtypeLocale="ne" + android:imeSubtypeLocale="ne_NP" android:imeSubtypeMode="keyboard" android:imeSubtypeExtraValue="KeyboardLayoutSet=nepali_romanized,EmojiCapable" android:isAsciiCapable="false" @@ -463,7 +463,7 @@ <subtype android:icon="@drawable/ic_ime_switcher_dark" android:label="@string/subtype_nepali_traditional" android:subtypeId="0x5fafea88" - android:imeSubtypeLocale="ne" + android:imeSubtypeLocale="ne_NP" android:imeSubtypeMode="keyboard" android:imeSubtypeExtraValue="KeyboardLayoutSet=nepali_traditional,EmojiCapable" android:isAsciiCapable="false" diff --git a/java/src/com/android/inputmethod/keyboard/Key.java b/java/src/com/android/inputmethod/keyboard/Key.java index b975b9c70..c8c4d30ef 100644 --- a/java/src/com/android/inputmethod/keyboard/Key.java +++ b/java/src/com/android/inputmethod/keyboard/Key.java @@ -348,8 +348,7 @@ public class Key implements Comparable<Key> { if (StringUtils.codePointCount(mLabel) == 1) { // Use the first letter of the hint label if shiftedLetterActivated flag is // specified. - if (hasShiftedLetterHint() && isShiftedLetterActivated() - && !TextUtils.isEmpty(mHintLabel)) { + if (hasShiftedLetterHint() && isShiftedLetterActivated()) { mCode = mHintLabel.codePointAt(0); } else { mCode = mLabel.codePointAt(0); @@ -687,7 +686,8 @@ public class Key implements Comparable<Key> { } public final boolean hasShiftedLetterHint() { - return (mLabelFlags & LABEL_FLAGS_HAS_SHIFTED_LETTER_HINT) != 0; + return (mLabelFlags & LABEL_FLAGS_HAS_SHIFTED_LETTER_HINT) != 0 + && !TextUtils.isEmpty(mHintLabel); } public final boolean hasHintLabel() { @@ -710,8 +710,9 @@ public class Key implements Comparable<Key> { return (mLabelFlags & LABEL_FLAGS_AUTO_SCALE) == LABEL_FLAGS_AUTO_SCALE; } - public final boolean isShiftedLetterActivated() { - return (mLabelFlags & LABEL_FLAGS_SHIFTED_LETTER_ACTIVATED) != 0; + private final boolean isShiftedLetterActivated() { + return (mLabelFlags & LABEL_FLAGS_SHIFTED_LETTER_ACTIVATED) != 0 + && !TextUtils.isEmpty(mHintLabel); } public final int getMoreKeysColumn() { diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java index dd98c1703..0c80ce206 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java @@ -304,6 +304,7 @@ public final class KeyboardState { mSwitchActions.setSymbolsKeyboard(); mIsAlphabetMode = false; mIsSymbolShifted = false; + mRecapitalizeMode = RecapitalizeStatus.NOT_A_RECAPITALIZE_MODE; // Reset alphabet shift state. mAlphabetShiftState.setShiftLocked(false); mSwitchState = SWITCH_STATE_SYMBOL_BEGIN; @@ -316,6 +317,7 @@ public final class KeyboardState { mSwitchActions.setSymbolsShiftedKeyboard(); mIsAlphabetMode = false; mIsSymbolShifted = true; + mRecapitalizeMode = RecapitalizeStatus.NOT_A_RECAPITALIZE_MODE; // Reset alphabet shift state. mAlphabetShiftState.setShiftLocked(false); mSwitchState = SWITCH_STATE_SYMBOL_BEGIN; @@ -327,6 +329,7 @@ public final class KeyboardState { } mIsAlphabetMode = false; mIsEmojiMode = true; + mRecapitalizeMode = RecapitalizeStatus.NOT_A_RECAPITALIZE_MODE; // Remember caps lock mode and reset alphabet shift state. mPrevMainKeyboardWasShiftLocked = mAlphabetShiftState.isShiftLocked(); mAlphabetShiftState.setShiftLocked(false); diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java index 1b722c5ce..f708c2cdd 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java @@ -635,8 +635,8 @@ public final class KeyboardTextsSet { /* 118 */ "\\%,\u2030", }; - /* Language az: Azerbaijani */ - private static final String[] LANGUAGE_az = { + /* Language az_AZ: Azerbaijani (Azerbaijan) */ + private static final String[] LANGUAGE_az_AZ = { // U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX /* 0 */ "\u00E2", // U+0259: "ə" LATIN SMALL LETTER SCHWA @@ -2454,8 +2454,8 @@ public final class KeyboardTextsSet { /* 53 */ "!text/double_9qm_rqm", }; - /* Language ne: Nepali */ - private static final String[] LANGUAGE_ne = { + /* Language ne_NP: Nepali (Nepal) */ + private static final String[] LANGUAGE_ne_NP = { /* 0~ */ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, @@ -3519,7 +3519,7 @@ public final class KeyboardTextsSet { "DEFAULT", LANGUAGE_DEFAULT, /* default */ "af", LANGUAGE_af, /* Afrikaans */ "ar", LANGUAGE_ar, /* Arabic */ - "az", LANGUAGE_az, /* Azerbaijani */ + "az" /* "az_AZ" */, LANGUAGE_az_AZ, /* Azerbaijani (Azerbaijan) */ "be" /* "be_BY" */, LANGUAGE_be_BY, /* Belarusian (Belarus) */ "bg", LANGUAGE_bg, /* Bulgarian */ "ca", LANGUAGE_ca, /* Catalan */ @@ -3551,7 +3551,7 @@ public final class KeyboardTextsSet { "mk", LANGUAGE_mk, /* Macedonian */ "mn" /* "mn_MN" */, LANGUAGE_mn_MN, /* Mongolian (Mongolia) */ "nb", LANGUAGE_nb, /* Norwegian Bokmål */ - "ne", LANGUAGE_ne, /* Nepali */ + "ne" /* "ne_NP" */, LANGUAGE_ne_NP, /* Nepali (Nepal) */ "nl", LANGUAGE_nl, /* Dutch */ "pl", LANGUAGE_pl, /* Polish */ "pt", LANGUAGE_pt, /* Portuguese */ diff --git a/java/src/com/android/inputmethod/latin/AbstractDictionaryWriter.java b/java/src/com/android/inputmethod/latin/AbstractDictionaryWriter.java index e6fb9807e..1aee22baf 100644 --- a/java/src/com/android/inputmethod/latin/AbstractDictionaryWriter.java +++ b/java/src/com/android/inputmethod/latin/AbstractDictionaryWriter.java @@ -21,7 +21,7 @@ import android.util.Log; import com.android.inputmethod.latin.makedict.DictEncoder; import com.android.inputmethod.latin.makedict.UnsupportedFormatException; -import com.android.inputmethod.latin.makedict.Ver3DictEncoder; +import com.android.inputmethod.latin.makedict.Ver2DictEncoder; import java.io.File; import java.io.IOException; @@ -64,7 +64,7 @@ abstract public class AbstractDictionaryWriter { final String tempFilePath = file.getAbsolutePath() + ".temp"; final File tempFile = new File(tempFilePath); try { - final DictEncoder dictEncoder = new Ver3DictEncoder(tempFile); + final DictEncoder dictEncoder = new Ver2DictEncoder(tempFile); writeDictionary(dictEncoder, attributeMap); tempFile.renameTo(file); } catch (IOException e) { diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java index db4234c63..95ac3e203 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java @@ -367,6 +367,7 @@ public final class BinaryDictionary extends Dictionary { public static class LanguageModelParam { public final int[] mWord0; public final int[] mWord1; + // TODO: this needs to be a list of shortcuts public final int[] mShortcutTarget; public final int mUnigramProbability; public final int mBigramProbability; @@ -375,7 +376,7 @@ public final class BinaryDictionary extends Dictionary { public final boolean mIsBlacklisted; public final int mTimestamp; - // Constructor for unigram. + // Constructor for unigram. TODO: support shortcuts public LanguageModelParam(final String word, final int unigramProbability, final int timestamp) { mWord0 = null; diff --git a/java/src/com/android/inputmethod/latin/DictionaryWriter.java b/java/src/com/android/inputmethod/latin/DictionaryWriter.java index f960c5343..89ef96d7f 100644 --- a/java/src/com/android/inputmethod/latin/DictionaryWriter.java +++ b/java/src/com/android/inputmethod/latin/DictionaryWriter.java @@ -18,8 +18,6 @@ package com.android.inputmethod.latin; import android.content.Context; -import com.android.inputmethod.keyboard.ProximityInfo; -import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; import com.android.inputmethod.latin.makedict.DictEncoder; import com.android.inputmethod.latin.makedict.FormatSpec; import com.android.inputmethod.latin.makedict.FusionDictionary; @@ -52,7 +50,7 @@ public class DictionaryWriter extends AbstractDictionaryWriter { public void clear() { final HashMap<String, String> attributes = CollectionUtils.newHashMap(); mFusionDictionary = new FusionDictionary(new PtNodeArray(), - new FusionDictionary.DictionaryOptions(attributes, false, false)); + new FusionDictionary.DictionaryOptions(attributes)); } /** diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 6a10131b0..8b466559c 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -100,7 +100,6 @@ import com.android.inputmethod.latin.utils.RecapitalizeStatus; import com.android.inputmethod.latin.utils.StringUtils; import com.android.inputmethod.latin.utils.TargetPackageInfoGetterTask; import com.android.inputmethod.latin.utils.TextRange; -import com.android.inputmethod.latin.utils.UserHistoryForgettingCurveUtils; import com.android.inputmethod.research.ResearchLogger; import java.io.FileDescriptor; @@ -1019,11 +1018,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen // Only for debug mBoostPersonalizationDictionaryForDebug = currentSettingsValues.mBoostPersonalizationDictionaryForDebug; - if (mBoostPersonalizationDictionaryForDebug) { - UserHistoryForgettingCurveUtils.boostMaxFreqForDebug(); - } else { - UserHistoryForgettingCurveUtils.resetMaxFreqForDebug(); - } } } @@ -1475,6 +1469,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen ResearchLogger.latinIME_maybeDoubleSpacePeriod(textToInsert, false /* isBatchMode */); } + mWordComposer.doubleSpacePeriod(); mKeyboardSwitcher.updateShiftState(); return true; } @@ -1799,10 +1794,19 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen final int codePointBeforeCursor = mConnection.getCodePointBeforeCursor(); if (Character.isLetterOrDigit(codePointBeforeCursor) || currentSettingsValues.isUsuallyFollowedBySpace(codePointBeforeCursor)) { + final boolean autoShiftHasBeenOverriden = mKeyboardSwitcher.getKeyboardShiftMode() != + getCurrentAutoCapsState(); mSpaceState = SPACE_STATE_PHANTOM; + if (!autoShiftHasBeenOverriden) { + // When we change the space state, we need to update the shift state of the + // keyboard unless it has been overridden manually. This is happening for example + // after typing some letters and a period, then gesturing; the keyboard is not in + // caps mode yet, but since a gesture is starting, it should go in caps mode, + // unless the user explictly said it should not. + mKeyboardSwitcher.updateShiftState(); + } } mConnection.endBatchEdit(); - mKeyboardSwitcher.updateShiftState(); mWordComposer.setCapitalizedModeAndPreviousWordAtStartComposingTime(getActualCapsMode(), // Prev word is 1st word before cursor getNthPreviousWordForSuggestion(currentSettingsValues, 1 /* nthPreviousWord */)); diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index 2f81d15d5..5ecfc67b2 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -471,7 +471,12 @@ public final class WordComposer { mCapsCount = 0; mDigitsCount = 0; mIsBatchMode = false; - mPreviousWord = mTypedWord.toString(); + final boolean isWhitespace = 1 == StringUtils.codePointCount(separatorString) + && Character.isWhitespace(separatorString.codePointAt(0)); + // If not whitespace, we don't use the previous word for suggestion. This is consistent + // with how we get the previous word for suggestion: see RichInputConnection#spaceRegex and + // LatinIME#getNthPreviousWordForSuggestion. + mPreviousWord = isWhitespace ? mTypedWord.toString() : null; mTypedWord.setLength(0); mCodePointSize = 0; mTrailingSingleQuotesCount = 0; @@ -485,6 +490,13 @@ public final class WordComposer { return lastComposedWord; } + public void doubleSpacePeriod() { + // When a period was entered with a double space, the separator we got has been + // changed by a period (see #commitWord). We should not use the previous word for + // suggestion. + mPreviousWord = null; + } + public void resumeSuggestionOnLastComposedWord(final LastComposedWord lastComposedWord, final String previousWord) { mPrimaryKeyCodes = lastComposedWord.mPrimaryKeyCodes; diff --git a/java/src/com/android/inputmethod/latin/makedict/AbstractDictDecoder.java b/java/src/com/android/inputmethod/latin/makedict/AbstractDictDecoder.java index bbbb8e461..f8fa68f45 100644 --- a/java/src/com/android/inputmethod/latin/makedict/AbstractDictDecoder.java +++ b/java/src/com/android/inputmethod/latin/makedict/AbstractDictDecoder.java @@ -58,12 +58,9 @@ public abstract class AbstractDictDecoder implements DictDecoder { headerSize); final FileHeader header = new FileHeader(headerSize, - new FusionDictionary.DictionaryOptions(attributes, - 0 != (optionsFlags & FormatSpec.GERMAN_UMLAUT_PROCESSING_FLAG), - 0 != (optionsFlags & FormatSpec.FRENCH_LIGATURE_PROCESSING_FLAG)), - new FormatOptions(version, - 0 != (optionsFlags & FormatSpec.SUPPORTS_DYNAMIC_UPDATE), - 0 != (optionsFlags & FormatSpec.CONTAINS_TIMESTAMP_FLAG))); + new FusionDictionary.DictionaryOptions(attributes), + new FormatOptions(version, + 0 != (optionsFlags & FormatSpec.CONTAINS_TIMESTAMP_FLAG))); return header; } diff --git a/java/src/com/android/inputmethod/latin/makedict/BinaryDictDecoderUtils.java b/java/src/com/android/inputmethod/latin/makedict/BinaryDictDecoderUtils.java index 83ee7d685..7f0aa777f 100644 --- a/java/src/com/android/inputmethod/latin/makedict/BinaryDictDecoderUtils.java +++ b/java/src/com/android/inputmethod/latin/makedict/BinaryDictDecoderUtils.java @@ -330,7 +330,7 @@ public final class BinaryDictDecoderUtils { static int readChildrenAddress(final DictBuffer dictBuffer, final int optionFlags, final FormatOptions options) { - if (options.mSupportsDynamicUpdate) { + if (options.supportsDynamicUpdate()) { final int address = dictBuffer.readUnsignedInt24(); if (address == 0) return FormatSpec.NO_CHILDREN_ADDRESS; if ((address & FormatSpec.MSB24) != 0) { @@ -540,11 +540,11 @@ public final class BinaryDictDecoderUtils { } // reach the end of the array. - if (options.mSupportsDynamicUpdate) { + if (options.supportsDynamicUpdate()) { final boolean hasValidForwardLink = dictDecoder.readAndFollowForwardLink(); if (!hasValidForwardLink) break; } - } while (options.mSupportsDynamicUpdate && dictDecoder.hasNextPtNodeArray()); + } while (options.supportsDynamicUpdate() && dictDecoder.hasNextPtNodeArray()); final PtNodeArray nodeArray = new PtNodeArray(nodeArrayContents); nodeArray.mCachedAddressBeforeUpdate = nodeArrayOriginPos; diff --git a/java/src/com/android/inputmethod/latin/makedict/BinaryDictEncoderUtils.java b/java/src/com/android/inputmethod/latin/makedict/BinaryDictEncoderUtils.java index c0dad3db2..8ba0797de 100644 --- a/java/src/com/android/inputmethod/latin/makedict/BinaryDictEncoderUtils.java +++ b/java/src/com/android/inputmethod/latin/makedict/BinaryDictEncoderUtils.java @@ -20,7 +20,6 @@ import com.android.inputmethod.latin.makedict.BinaryDictDecoderUtils.CharEncodin import com.android.inputmethod.latin.makedict.BinaryDictDecoderUtils.DictBuffer; import com.android.inputmethod.latin.makedict.FormatSpec.FormatOptions; import com.android.inputmethod.latin.makedict.FusionDictionary.PtNode; -import com.android.inputmethod.latin.makedict.FusionDictionary.DictionaryOptions; import com.android.inputmethod.latin.makedict.FusionDictionary.PtNodeArray; import com.android.inputmethod.latin.makedict.FusionDictionary.WeightedString; @@ -161,7 +160,7 @@ public class BinaryDictEncoderUtils { node.mCachedSize = nodeSize; size += nodeSize; } - if (options.mSupportsDynamicUpdate) { + if (options.supportsDynamicUpdate()) { size += FormatSpec.FORWARD_LINK_ADDRESS_SIZE; } ptNodeArray.mCachedSize = size; @@ -398,7 +397,7 @@ public class BinaryDictEncoderUtils { nodeSize += FormatSpec.PTNODE_FREQUENCY_SIZE; } } - if (formatOptions.mSupportsDynamicUpdate) { + if (formatOptions.supportsDynamicUpdate()) { nodeSize += FormatSpec.SIGNED_CHILDREN_ADDRESS_SIZE; } else if (null != ptNode.mChildren) { nodeSize += getByteSize(getOffsetToTargetNodeArrayDuringUpdate(ptNodeArray, @@ -418,7 +417,7 @@ public class BinaryDictEncoderUtils { ptNode.mCachedSize = nodeSize; size += nodeSize; } - if (formatOptions.mSupportsDynamicUpdate) { + if (formatOptions.supportsDynamicUpdate()) { size += FormatSpec.FORWARD_LINK_ADDRESS_SIZE; } if (ptNodeArray.mCachedSize != size) { @@ -534,7 +533,7 @@ public class BinaryDictEncoderUtils { if (passes > MAX_PASSES) throw new RuntimeException("Too many passes - probably a bug"); } while (changesDone); - if (formatOptions.mSupportsDynamicUpdate) { + if (formatOptions.supportsDynamicUpdate()) { computeParentAddresses(flatNodes); } final PtNodeArray lastPtNodeArray = flatNodes.get(flatNodes.size() - 1); @@ -643,7 +642,7 @@ public class BinaryDictEncoderUtils { byte flags = 0; if (hasMultipleChars) flags |= FormatSpec.FLAG_HAS_MULTIPLE_CHARS; if (isTerminal) flags |= FormatSpec.FLAG_IS_TERMINAL; - if (formatOptions.mSupportsDynamicUpdate) { + if (formatOptions.supportsDynamicUpdate()) { flags |= FormatSpec.FLAG_IS_NOT_MOVED; } else if (true) { switch (childrenAddressSize) { @@ -755,16 +754,11 @@ public class BinaryDictEncoderUtils { } /** - * Makes the 2-byte value for options flags. + * Makes the 2-byte value for options flags. Unused at the moment, and always 0. */ - private static final int makeOptionsValue(final FusionDictionary dictionary, - final FormatOptions formatOptions) { - final DictionaryOptions options = dictionary.mOptions; - final boolean hasBigrams = dictionary.hasBigrams(); - return (options.mFrenchLigatureProcessing ? FormatSpec.FRENCH_LIGATURE_PROCESSING_FLAG : 0) - + (options.mGermanUmlautProcessing ? FormatSpec.GERMAN_UMLAUT_PROCESSING_FLAG : 0) - + (hasBigrams ? FormatSpec.CONTAINS_BIGRAMS_FLAG : 0) - + (formatOptions.mSupportsDynamicUpdate ? FormatSpec.SUPPORTS_DYNAMIC_UPDATE : 0); + private static final int makeOptionsValue(final FormatOptions formatOptions) { + // TODO: why doesn't this handle CONTAINS_TIMESTAMP_FLAG? + return 0; } /** @@ -852,7 +846,7 @@ public class BinaryDictEncoderUtils { } dictEncoder.writePtNode(ptNode, parentPosition, formatOptions, dict); } - if (formatOptions.mSupportsDynamicUpdate) { + if (formatOptions.supportsDynamicUpdate()) { dictEncoder.writeForwardLinkAddress(FormatSpec.NO_FORWARD_LINK_ADDRESS); } if (dictEncoder.getPosition() != ptNodeArray.mCachedAddressAfterUpdate @@ -953,7 +947,7 @@ public class BinaryDictEncoderUtils { headerBuffer.write((byte) (0xFF & version)); // Options flags - final int options = makeOptionsValue(dict, formatOptions); + final int options = makeOptionsValue(formatOptions); headerBuffer.write((byte) (0xFF & (options >> 8))); headerBuffer.write((byte) (0xFF & options)); final int headerSizeOffset = headerBuffer.size(); diff --git a/java/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtils.java b/java/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtils.java index 86ebf5844..640d778bb 100644 --- a/java/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtils.java +++ b/java/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtils.java @@ -112,7 +112,7 @@ public final class BinaryDictIOUtils { } if (p.mPosition == p.mNumOfPtNode) { - if (formatOptions.mSupportsDynamicUpdate) { + if (formatOptions.supportsDynamicUpdate()) { final boolean hasValidForwardLinkAddress = dictDecoder.readAndFollowForwardLink(); if (hasValidForwardLinkAddress && dictDecoder.hasNextPtNodeArray()) { @@ -228,7 +228,7 @@ public final class BinaryDictIOUtils { // a forward link address that we need to consult and possibly resume // search on the next node array in the linked list. if (foundNextPtNode) break; - if (!header.mFormatOptions.mSupportsDynamicUpdate) { + if (!header.mFormatOptions.supportsDynamicUpdate()) { return FormatSpec.NOT_VALID_WORD; } @@ -507,7 +507,7 @@ public final class BinaryDictIOUtils { * Helper method to check whether the node is moved. */ public static boolean isMovedPtNode(final int flags, final FormatOptions options) { - return options.mSupportsDynamicUpdate + return options.supportsDynamicUpdate() && ((flags & FormatSpec.MASK_CHILDREN_ADDRESS_TYPE) == FormatSpec.FLAG_IS_MOVED); } @@ -516,14 +516,14 @@ public final class BinaryDictIOUtils { */ public static boolean supportsDynamicUpdate(final FormatOptions options) { return options.mVersion >= FormatSpec.FIRST_VERSION_WITH_DYNAMIC_UPDATE - && options.mSupportsDynamicUpdate; + && options.supportsDynamicUpdate(); } /** * Helper method to check whether the node is deleted. */ public static boolean isDeletedPtNode(final int flags, final FormatOptions formatOptions) { - return formatOptions.mSupportsDynamicUpdate + return formatOptions.supportsDynamicUpdate() && ((flags & FormatSpec.MASK_CHILDREN_ADDRESS_TYPE) == FormatSpec.FLAG_IS_DELETED); } @@ -546,7 +546,7 @@ public final class BinaryDictIOUtils { static int getChildrenAddressSize(final int optionFlags, final FormatOptions formatOptions) { - if (formatOptions.mSupportsDynamicUpdate) return FormatSpec.SIGNED_CHILDREN_ADDRESS_SIZE; + if (formatOptions.supportsDynamicUpdate()) return FormatSpec.SIGNED_CHILDREN_ADDRESS_SIZE; switch (optionFlags & FormatSpec.MASK_CHILDREN_ADDRESS_TYPE) { case FormatSpec.FLAG_CHILDREN_ADDRESS_TYPE_ONEBYTE: return 1; diff --git a/java/src/com/android/inputmethod/latin/makedict/DynamicBinaryDictIOUtils.java b/java/src/com/android/inputmethod/latin/makedict/DynamicBinaryDictIOUtils.java deleted file mode 100644 index 971b4ff9f..000000000 --- a/java/src/com/android/inputmethod/latin/makedict/DynamicBinaryDictIOUtils.java +++ /dev/null @@ -1,492 +0,0 @@ -/* - * Copyright (C) 2013 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.makedict; - -import com.android.inputmethod.annotations.UsedForTesting; -import com.android.inputmethod.latin.Constants; -import com.android.inputmethod.latin.makedict.BinaryDictDecoderUtils.DictBuffer; -import com.android.inputmethod.latin.makedict.FormatSpec.FileHeader; -import com.android.inputmethod.latin.makedict.FormatSpec.FormatOptions; -import com.android.inputmethod.latin.makedict.FusionDictionary.WeightedString; -import com.android.inputmethod.latin.utils.CollectionUtils; - -import java.io.IOException; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.Arrays; - -/** - * The utility class to help dynamic updates on the binary dictionary. - * - * All the methods in this class are static. - */ -@UsedForTesting -public final class DynamicBinaryDictIOUtils { - private static final boolean DBG = false; - static final int MAX_JUMPS = 10000; - - private DynamicBinaryDictIOUtils() { - // This utility class is not publicly instantiable. - } - - /* package */ static int markAsDeleted(final int flags) { - return (flags & (~FormatSpec.MASK_CHILDREN_ADDRESS_TYPE)) | FormatSpec.FLAG_IS_DELETED; - } - - /** - * Update a parent address in a PtNode that is referred to by ptNodeOriginAddress. - * - * @param dictUpdater the DictUpdater to write. - * @param ptNodeOriginAddress the address of the PtNode. - * @param newParentAddress the absolute address of the parent. - * @param formatOptions file format options. - */ - private static void updateParentAddress(final Ver3DictUpdater dictUpdater, - final int ptNodeOriginAddress, final int newParentAddress, - final FormatOptions formatOptions) { - final DictBuffer dictBuffer = dictUpdater.getDictBuffer(); - final int originalPosition = dictBuffer.position(); - dictBuffer.position(ptNodeOriginAddress); - if (!formatOptions.mSupportsDynamicUpdate) { - throw new RuntimeException("this file format does not support parent addresses"); - } - final int flags = dictBuffer.readUnsignedByte(); - if (BinaryDictIOUtils.isMovedPtNode(flags, formatOptions)) { - // If the node is moved, the parent address is stored in the destination node. - // We are guaranteed to process the destination node later, so there is no need to - // update anything here. - dictBuffer.position(originalPosition); - return; - } - if (DBG) { - MakedictLog.d("update parent address flags=" + flags + ", " + ptNodeOriginAddress); - } - final int parentOffset = newParentAddress - ptNodeOriginAddress; - BinaryDictIOUtils.writeSInt24ToBuffer(dictBuffer, parentOffset); - dictBuffer.position(originalPosition); - } - - /** - * Update parent addresses in a node array stored at ptNodeOriginAddress. - * - * @param dictUpdater the DictUpdater to be modified. - * @param ptNodeOriginAddress the address of the node array to update. - * @param newParentAddress the address to be written. - * @param formatOptions file format options. - */ - private static void updateParentAddresses(final Ver3DictUpdater dictUpdater, - final int ptNodeOriginAddress, final int newParentAddress, - final FormatOptions formatOptions) { - final int originalPosition = dictUpdater.getPosition(); - dictUpdater.setPosition(ptNodeOriginAddress); - do { - final int count = dictUpdater.readPtNodeCount(); - for (int i = 0; i < count; ++i) { - updateParentAddress(dictUpdater, dictUpdater.getPosition(), newParentAddress, - formatOptions); - dictUpdater.skipPtNode(formatOptions); - } - if (!dictUpdater.readAndFollowForwardLink()) break; - if (dictUpdater.getPosition() == FormatSpec.NO_FORWARD_LINK_ADDRESS) break; - } while (formatOptions.mSupportsDynamicUpdate); - dictUpdater.setPosition(originalPosition); - } - - /** - * Update a children address in a PtNode that is addressed by ptNodeOriginAddress. - * - * @param dictUpdater the DictUpdater to write. - * @param ptNodeOriginAddress the address of the PtNode. - * @param newChildrenAddress the absolute address of the child. - * @param formatOptions file format options. - */ - private static void updateChildrenAddress(final Ver3DictUpdater dictUpdater, - final int ptNodeOriginAddress, final int newChildrenAddress, - final FormatOptions formatOptions) { - final DictBuffer dictBuffer = dictUpdater.getDictBuffer(); - final int originalPosition = dictBuffer.position(); - dictBuffer.position(ptNodeOriginAddress); - final int flags = dictBuffer.readUnsignedByte(); - BinaryDictDecoderUtils.readParentAddress(dictBuffer, formatOptions); - BinaryDictIOUtils.skipString(dictBuffer, (flags & FormatSpec.FLAG_HAS_MULTIPLE_CHARS) != 0); - if ((flags & FormatSpec.FLAG_IS_TERMINAL) != 0) dictBuffer.readUnsignedByte(); - final int childrenOffset = newChildrenAddress == FormatSpec.NO_CHILDREN_ADDRESS - ? FormatSpec.NO_CHILDREN_ADDRESS : newChildrenAddress - dictBuffer.position(); - BinaryDictIOUtils.writeSInt24ToBuffer(dictBuffer, childrenOffset); - dictBuffer.position(originalPosition); - } - - /** - * Helper method to move a PtNode to the tail of the file. - */ - private static int movePtNode(final OutputStream destination, - final Ver3DictUpdater dictUpdater, final PtNodeInfo info, - final int nodeArrayOriginAddress, final int oldNodeAddress, - final FormatOptions formatOptions) throws IOException { - final DictBuffer dictBuffer = dictUpdater.getDictBuffer(); - updateParentAddress(dictUpdater, oldNodeAddress, dictBuffer.limit() + 1, formatOptions); - dictBuffer.position(oldNodeAddress); - final int currentFlags = dictBuffer.readUnsignedByte(); - dictBuffer.position(oldNodeAddress); - dictBuffer.put((byte)(FormatSpec.FLAG_IS_MOVED | (currentFlags - & (~FormatSpec.MASK_MOVE_AND_DELETE_FLAG)))); - int size = FormatSpec.PTNODE_FLAGS_SIZE; - updateForwardLink(dictUpdater, nodeArrayOriginAddress, dictBuffer.limit(), formatOptions); - size += BinaryDictIOUtils.writeNodes(destination, new PtNodeInfo[] { info }); - return size; - } - - @SuppressWarnings("unused") - private static void updateForwardLink(final Ver3DictUpdater dictUpdater, - final int nodeArrayOriginAddress, final int newNodeArrayAddress, - final FormatOptions formatOptions) { - final DictBuffer dictBuffer = dictUpdater.getDictBuffer(); - dictUpdater.setPosition(nodeArrayOriginAddress); - int jumpCount = 0; - while (jumpCount++ < MAX_JUMPS) { - final int count = dictUpdater.readPtNodeCount(); - for (int i = 0; i < count; ++i) { - dictUpdater.readPtNode(dictUpdater.getPosition(), formatOptions); - } - final int forwardLinkAddress = dictBuffer.readUnsignedInt24(); - if (forwardLinkAddress == FormatSpec.NO_FORWARD_LINK_ADDRESS) { - dictBuffer.position(dictBuffer.position() - FormatSpec.FORWARD_LINK_ADDRESS_SIZE); - BinaryDictIOUtils.writeSInt24ToBuffer(dictBuffer, newNodeArrayAddress); - return; - } - dictBuffer.position(forwardLinkAddress); - } - if (DBG && jumpCount >= MAX_JUMPS) { - throw new RuntimeException("too many jumps, probably a bug."); - } - } - - /** - * Move a PtNode that is referred to by oldPtNodeOrigin to the tail of the file, and set the - * children address to the byte after the PtNode. - * - * @param fileEndAddress the address of the tail of the file. - * @param codePoints the characters to put inside the PtNode. - * @param length how many code points to read from codePoints. - * @param flags the flags for this PtNode. - * @param frequency the frequency of this terminal. - * @param parentAddress the address of the parent PtNode of this PtNode. - * @param shortcutTargets the shortcut targets for this PtNode. - * @param bigrams the bigrams for this PtNode. - * @param destination the stream representing the tail of the file. - * @param dictUpdater the DictUpdater. - * @param oldPtNodeArrayOrigin the origin of the old PtNode array this PtNode was a part of. - * @param oldPtNodeOrigin the old origin where this PtNode used to be stored. - * @param formatOptions format options for this dictionary. - * @return the size written, in bytes. - * @throws IOException if the file can't be accessed - */ - private static int movePtNode(final int fileEndAddress, final int[] codePoints, - final int length, final int flags, final int frequency, final int parentAddress, - final ArrayList<WeightedString> shortcutTargets, - final ArrayList<PendingAttribute> bigrams, final OutputStream destination, - final Ver3DictUpdater dictUpdater, final int oldPtNodeArrayOrigin, - final int oldPtNodeOrigin, final FormatOptions formatOptions) throws IOException { - int size = 0; - final int newPtNodeOrigin = fileEndAddress + 1; - final int[] writtenCharacters = Arrays.copyOfRange(codePoints, 0, length); - final PtNodeInfo tmpInfo = new PtNodeInfo(newPtNodeOrigin, -1 /* endAddress */, - flags, writtenCharacters, frequency, parentAddress, FormatSpec.NO_CHILDREN_ADDRESS, - shortcutTargets, bigrams); - size = BinaryDictIOUtils.computePtNodeSize(tmpInfo, formatOptions); - final PtNodeInfo newInfo = new PtNodeInfo(newPtNodeOrigin, newPtNodeOrigin + size, - flags, writtenCharacters, frequency, parentAddress, - fileEndAddress + 1 + size + FormatSpec.FORWARD_LINK_ADDRESS_SIZE, shortcutTargets, - bigrams); - movePtNode(destination, dictUpdater, newInfo, oldPtNodeArrayOrigin, oldPtNodeOrigin, - formatOptions); - return 1 + size + FormatSpec.FORWARD_LINK_ADDRESS_SIZE; - } - - /** - * Converts a list of WeightedString to a list of PendingAttribute. - */ - public static ArrayList<PendingAttribute> resolveBigramPositions(final DictUpdater dictUpdater, - final ArrayList<WeightedString> bigramStrings) - throws IOException, UnsupportedFormatException { - if (bigramStrings == null) return CollectionUtils.newArrayList(); - final ArrayList<PendingAttribute> bigrams = CollectionUtils.newArrayList(); - for (final WeightedString bigram : bigramStrings) { - final int pos = dictUpdater.getTerminalPosition(bigram.mWord); - if (pos == FormatSpec.NOT_VALID_WORD) { - // TODO: figure out what is the correct thing to do here. - } else { - bigrams.add(new PendingAttribute(bigram.mFrequency, pos)); - } - } - return bigrams; - } - - /** - * Insert a word into a binary dictionary. - * - * @param dictUpdater the dict updater. - * @param destination a stream to the underlying file, with the pointer at the end of the file. - * @param word the word to insert. - * @param frequency the frequency of the new word. - * @param bigramStrings bigram list, or null if none. - * @param shortcuts shortcut list, or null if none. - * @param isBlackListEntry whether this should be a blacklist entry. - * @throws IOException if the file can't be accessed. - * @throws UnsupportedFormatException if the existing dictionary is in an unexpected format. - */ - // TODO: Support batch insertion. - // TODO: Remove @UsedForTesting once UserHistoryDictionary is implemented by BinaryDictionary. - @UsedForTesting - public static void insertWord(final Ver3DictUpdater dictUpdater, - final OutputStream destination, final String word, final int frequency, - final ArrayList<WeightedString> bigramStrings, - final ArrayList<WeightedString> shortcuts, final boolean isNotAWord, - final boolean isBlackListEntry) - throws IOException, UnsupportedFormatException { - final ArrayList<PendingAttribute> bigrams = resolveBigramPositions(dictUpdater, - bigramStrings); - final DictBuffer dictBuffer = dictUpdater.getDictBuffer(); - - final boolean isTerminal = true; - final boolean hasBigrams = !bigrams.isEmpty(); - final boolean hasShortcuts = shortcuts != null && !shortcuts.isEmpty(); - - // find the insert position of the word. - if (dictBuffer.position() != 0) dictBuffer.position(0); - final FileHeader fileHeader = dictUpdater.readHeader(); - - int wordPos = 0, address = dictBuffer.position(), nodeOriginAddress = dictBuffer.position(); - final int[] codePoints = FusionDictionary.getCodePoints(word); - final int wordLen = codePoints.length; - - for (int depth = 0; depth < Constants.DICTIONARY_MAX_WORD_LENGTH; ++depth) { - if (wordPos >= wordLen) break; - nodeOriginAddress = dictBuffer.position(); - int nodeParentAddress = -1; - final int ptNodeCount = BinaryDictDecoderUtils.readPtNodeCount(dictBuffer); - boolean foundNextNode = false; - - for (int i = 0; i < ptNodeCount; ++i) { - address = dictBuffer.position(); - final PtNodeInfo currentInfo = dictUpdater.readPtNode(address, - fileHeader.mFormatOptions); - final boolean isMovedNode = BinaryDictIOUtils.isMovedPtNode(currentInfo.mFlags, - fileHeader.mFormatOptions); - if (isMovedNode) continue; - nodeParentAddress = (currentInfo.mParentAddress == FormatSpec.NO_PARENT_ADDRESS) - ? FormatSpec.NO_PARENT_ADDRESS : currentInfo.mParentAddress + address; - boolean matched = true; - for (int p = 0; p < currentInfo.mCharacters.length; ++p) { - if (wordPos + p >= wordLen) { - /* - * splitting - * before - * abcd - ef - * - * insert "abc" - * - * after - * abc - d - ef - */ - final int newNodeAddress = dictBuffer.limit(); - final int flags = BinaryDictEncoderUtils.makePtNodeFlags(p > 1, - isTerminal, 0, hasShortcuts, hasBigrams, false /* isNotAWord */, - false /* isBlackListEntry */, fileHeader.mFormatOptions); - int written = movePtNode(newNodeAddress, currentInfo.mCharacters, p, flags, - frequency, nodeParentAddress, shortcuts, bigrams, destination, - dictUpdater, nodeOriginAddress, address, fileHeader.mFormatOptions); - - final int[] characters2 = Arrays.copyOfRange(currentInfo.mCharacters, p, - currentInfo.mCharacters.length); - if (currentInfo.mChildrenAddress != FormatSpec.NO_CHILDREN_ADDRESS) { - updateParentAddresses(dictUpdater, currentInfo.mChildrenAddress, - newNodeAddress + written + 1, fileHeader.mFormatOptions); - } - final PtNodeInfo newInfo2 = new PtNodeInfo( - newNodeAddress + written + 1, -1 /* endAddress */, - currentInfo.mFlags, characters2, currentInfo.mFrequency, - newNodeAddress + 1, currentInfo.mChildrenAddress, - currentInfo.mShortcutTargets, currentInfo.mBigrams); - BinaryDictIOUtils.writeNodes(destination, new PtNodeInfo[] { newInfo2 }); - return; - } else if (codePoints[wordPos + p] != currentInfo.mCharacters[p]) { - if (p > 0) { - /* - * splitting - * before - * ab - cd - * - * insert "ac" - * - * after - * a - b - cd - * | - * - c - */ - - final int newNodeAddress = dictBuffer.limit(); - final int childrenAddress = currentInfo.mChildrenAddress; - - // move prefix - final int prefixFlags = BinaryDictEncoderUtils.makePtNodeFlags(p > 1, - false /* isTerminal */, 0 /* childrenAddressSize*/, - false /* hasShortcut */, false /* hasBigrams */, - false /* isNotAWord */, false /* isBlackListEntry */, - fileHeader.mFormatOptions); - int written = movePtNode(newNodeAddress, currentInfo.mCharacters, p, - prefixFlags, -1 /* frequency */, nodeParentAddress, null, null, - destination, dictUpdater, nodeOriginAddress, address, - fileHeader.mFormatOptions); - - final int[] suffixCharacters = Arrays.copyOfRange( - currentInfo.mCharacters, p, currentInfo.mCharacters.length); - if (currentInfo.mChildrenAddress != FormatSpec.NO_CHILDREN_ADDRESS) { - updateParentAddresses(dictUpdater, currentInfo.mChildrenAddress, - newNodeAddress + written + 1, fileHeader.mFormatOptions); - } - final int suffixFlags = BinaryDictEncoderUtils.makePtNodeFlags( - suffixCharacters.length > 1, - (currentInfo.mFlags & FormatSpec.FLAG_IS_TERMINAL) != 0, - 0 /* childrenAddressSize */, - (currentInfo.mFlags & FormatSpec.FLAG_HAS_SHORTCUT_TARGETS) - != 0, - (currentInfo.mFlags & FormatSpec.FLAG_HAS_BIGRAMS) != 0, - isNotAWord, isBlackListEntry, fileHeader.mFormatOptions); - final PtNodeInfo suffixInfo = new PtNodeInfo( - newNodeAddress + written + 1, -1 /* endAddress */, suffixFlags, - suffixCharacters, currentInfo.mFrequency, newNodeAddress + 1, - currentInfo.mChildrenAddress, currentInfo.mShortcutTargets, - currentInfo.mBigrams); - written += BinaryDictIOUtils.computePtNodeSize(suffixInfo, - fileHeader.mFormatOptions) + 1; - - final int[] newCharacters = Arrays.copyOfRange(codePoints, wordPos + p, - codePoints.length); - final int flags = BinaryDictEncoderUtils.makePtNodeFlags( - newCharacters.length > 1, isTerminal, - 0 /* childrenAddressSize */, hasShortcuts, hasBigrams, - isNotAWord, isBlackListEntry, fileHeader.mFormatOptions); - final PtNodeInfo newInfo = new PtNodeInfo( - newNodeAddress + written, -1 /* endAddress */, flags, - newCharacters, frequency, newNodeAddress + 1, - FormatSpec.NO_CHILDREN_ADDRESS, shortcuts, bigrams); - BinaryDictIOUtils.writeNodes(destination, - new PtNodeInfo[] { suffixInfo, newInfo }); - return; - } - matched = false; - break; - } - } - - if (matched) { - if (wordPos + currentInfo.mCharacters.length == wordLen) { - // the word exists in the dictionary. - // only update the PtNode. - final int newNodeAddress = dictBuffer.limit(); - final boolean hasMultipleChars = currentInfo.mCharacters.length > 1; - final int flags = BinaryDictEncoderUtils.makePtNodeFlags(hasMultipleChars, - isTerminal, 0 /* childrenAddressSize */, hasShortcuts, hasBigrams, - isNotAWord, isBlackListEntry, fileHeader.mFormatOptions); - final PtNodeInfo newInfo = new PtNodeInfo(newNodeAddress + 1, - -1 /* endAddress */, flags, currentInfo.mCharacters, frequency, - nodeParentAddress, currentInfo.mChildrenAddress, shortcuts, - bigrams); - movePtNode(destination, dictUpdater, newInfo, nodeOriginAddress, address, - fileHeader.mFormatOptions); - return; - } - wordPos += currentInfo.mCharacters.length; - if (currentInfo.mChildrenAddress == FormatSpec.NO_CHILDREN_ADDRESS) { - /* - * found the prefix of the word. - * make new PtNode and link to the PtNode from this PtNode. - * - * before - * ab - cd - * - * insert "abcde" - * - * after - * ab - cd - e - */ - final int newNodeArrayAddress = dictBuffer.limit(); - updateChildrenAddress(dictUpdater, address, newNodeArrayAddress, - fileHeader.mFormatOptions); - final int newNodeAddress = newNodeArrayAddress + 1; - final boolean hasMultipleChars = (wordLen - wordPos) > 1; - final int flags = BinaryDictEncoderUtils.makePtNodeFlags(hasMultipleChars, - isTerminal, 0 /* childrenAddressSize */, hasShortcuts, hasBigrams, - isNotAWord, isBlackListEntry, fileHeader.mFormatOptions); - final int[] characters = Arrays.copyOfRange(codePoints, wordPos, wordLen); - final PtNodeInfo newInfo = new PtNodeInfo(newNodeAddress, -1, flags, - characters, frequency, address, FormatSpec.NO_CHILDREN_ADDRESS, - shortcuts, bigrams); - BinaryDictIOUtils.writeNodes(destination, new PtNodeInfo[] { newInfo }); - return; - } - dictBuffer.position(currentInfo.mChildrenAddress); - foundNextNode = true; - break; - } - } - - if (foundNextNode) continue; - - // reached the end of the array. - final int linkAddressPosition = dictBuffer.position(); - int nextLink = dictBuffer.readUnsignedInt24(); - if ((nextLink & FormatSpec.MSB24) != 0) { - nextLink = -(nextLink & FormatSpec.SINT24_MAX); - } - if (nextLink == FormatSpec.NO_FORWARD_LINK_ADDRESS) { - /* - * expand this node. - * - * before - * ab - cd - * - * insert "abef" - * - * after - * ab - cd - * | - * - ef - */ - - // change the forward link address. - final int newNodeAddress = dictBuffer.limit(); - dictBuffer.position(linkAddressPosition); - BinaryDictIOUtils.writeSInt24ToBuffer(dictBuffer, newNodeAddress); - - final int[] characters = Arrays.copyOfRange(codePoints, wordPos, wordLen); - final int flags = BinaryDictEncoderUtils.makePtNodeFlags(characters.length > 1, - isTerminal, 0 /* childrenAddressSize */, hasShortcuts, hasBigrams, - isNotAWord, isBlackListEntry, fileHeader.mFormatOptions); - final PtNodeInfo newInfo = new PtNodeInfo(newNodeAddress + 1, - -1 /* endAddress */, flags, characters, frequency, nodeParentAddress, - FormatSpec.NO_CHILDREN_ADDRESS, shortcuts, bigrams); - BinaryDictIOUtils.writeNodes(destination, new PtNodeInfo[]{ newInfo }); - return; - } else { - depth--; - dictBuffer.position(nextLink); - } - } - } -} diff --git a/java/src/com/android/inputmethod/latin/makedict/FormatSpec.java b/java/src/com/android/inputmethod/latin/makedict/FormatSpec.java index 846aacf11..2f6f194aa 100644 --- a/java/src/com/android/inputmethod/latin/makedict/FormatSpec.java +++ b/java/src/com/android/inputmethod/latin/makedict/FormatSpec.java @@ -40,12 +40,8 @@ public final class FormatSpec { * p | not used 3 bits * t | each unigram and bigram entry has a time stamp? * i | 1 bit, 1 = yes, 0 = no : CONTAINS_TIMESTAMP_FLAG - * o | has bigrams ? 1 bit, 1 = yes, 0 = no : CONTAINS_BIGRAMS_FLAG - * n | FRENCH_LIGATURE_PROCESSING_FLAG - * f | supports dynamic updates ? 1 bit, 1 = yes, 0 = no : SUPPORTS_DYNAMIC_UPDATE - * l | GERMAN_UMLAUT_PROCESSING_FLAG - * a | - * gs + * o | + * nflags * * h | * e | size of the file header, 4bytes @@ -82,45 +78,36 @@ public final class FormatSpec { * s * * f | - * o | IF SUPPORTS_DYNAMIC_UPDATE (defined in the file header) - * r | forward link address, 3byte - * w | 1 byte = bbbbbbbb match - * a | case 1xxxxxxx => -((xxxxxxx << 16) + (next byte << 8) + next byte) - * r | otherwise => (xxxxxxx << 16) + (next byte << 8) + next byte - * d | - * linkaddress + * o | forward link address, 3byte + * r | 1 byte = bbbbbbbb match + * w | case 1xxxxxxx => -((xxxxxxx << 16) + (next byte << 8) + next byte) + * a | otherwise => (xxxxxxx << 16) + (next byte << 8) + next byte + * r | + * dlinkaddress */ /* Node (FusionDictionary.PtNode) layout is as follows: - * | IF !SUPPORTS_DYNAMIC_UPDATE - * | addressType xx : mask with MASK_CHILDREN_ADDRESS_TYPE - * | 2 bits, 00 = no children : FLAG_CHILDREN_ADDRESS_TYPE_NOADDRESS - * f | 01 = 1 byte : FLAG_CHILDREN_ADDRESS_TYPE_ONEBYTE - * l | 10 = 2 bytes : FLAG_CHILDREN_ADDRESS_TYPE_TWOBYTES - * a | 11 = 3 bytes : FLAG_CHILDREN_ADDRESS_TYPE_THREEBYTES - * g | ELSE - * s | is moved ? 2 bits, 11 = no : FLAG_IS_NOT_MOVED - * | This must be the same as FLAG_CHILDREN_ADDRESS_TYPE_THREEBYTES - * | 01 = yes : FLAG_IS_MOVED - * | the new address is stored in the same place as the parent address - * | is deleted? 10 = yes : FLAG_IS_DELETED - * | has several chars ? 1 bit, 1 = yes, 0 = no : FLAG_HAS_MULTIPLE_CHARS - * | has a terminal ? 1 bit, 1 = yes, 0 = no : FLAG_IS_TERMINAL - * | has shortcut targets ? 1 bit, 1 = yes, 0 = no : FLAG_HAS_SHORTCUT_TARGETS + * | is moved ? 2 bits, 11 = no : FLAG_IS_NOT_MOVED + * | This must be the same as FLAG_CHILDREN_ADDRESS_TYPE_THREEBYTES + * | 01 = yes : FLAG_IS_MOVED + * f | the new address is stored in the same place as the parent address + * l | is deleted? 10 = yes : FLAG_IS_DELETED + * a | has several chars ? 1 bit, 1 = yes, 0 = no : FLAG_HAS_MULTIPLE_CHARS + * g | has a terminal ? 1 bit, 1 = yes, 0 = no : FLAG_IS_TERMINAL + * s | has shortcut targets ? 1 bit, 1 = yes, 0 = no : FLAG_HAS_SHORTCUT_TARGETS * | has bigrams ? 1 bit, 1 = yes, 0 = no : FLAG_HAS_BIGRAMS * | is not a word ? 1 bit, 1 = yes, 0 = no : FLAG_IS_NOT_A_WORD * | is blacklisted ? 1 bit, 1 = yes, 0 = no : FLAG_IS_BLACKLISTED * * p | - * a | IF SUPPORTS_DYNAMIC_UPDATE (defined in the file header) - * r | parent address, 3byte - * e | 1 byte = bbbbbbbb match - * n | case 1xxxxxxx => -((0xxxxxxx << 16) + (next byte << 8) + next byte) - * t | otherwise => (bbbbbbbb << 16) + (next byte << 8) + next byte - * a | This address is relative to the head of the PtNode. - * d | If the node doesn't have a parent, this field is set to 0. + * a | parent address, 3byte + * r | 1 byte = bbbbbbbb match + * e | case 1xxxxxxx => -((0xxxxxxx << 16) + (next byte << 8) + next byte) + * n | otherwise => (bbbbbbbb << 16) + (next byte << 8) + next byte + * t | This address is relative to the head of the PtNode. + * a | If the node doesn't have a parent, this field is set to 0. * d | - * ress + * dress * * c | IF FLAG_HAS_MULTIPLE_CHARS * h | char, char, char, char n * (1 or 3 bytes) : use PtNodeInfo for i/o helpers @@ -134,23 +121,16 @@ public final class FormatSpec { * e | frequency 1 byte * q | * - * c | IF SUPPORTS_DYNAMIC_UPDATE - * h | children address, 3 bytes - * i | 1 byte = bbbbbbbb match - * l | case 1xxxxxxx => -((0xxxxxxx << 16) + (next byte << 8) + next byte) - * d | otherwise => (bbbbbbbb<<16) + (next byte << 8) + next byte - * r | if this node doesn't have children, this field is set to 0. - * e | (see BinaryDictEncoderUtils#writeVariableSignedAddress) - * n | ELSIF 00 = FLAG_CHILDREN_ADDRESS_TYPE_NOADDRESS == addressType - * a | // nothing - * d | ELSIF 01 = FLAG_CHILDREN_ADDRESS_TYPE_ONEBYTE == addressType - * d | children address, 1 byte - * r | ELSIF 10 = FLAG_CHILDREN_ADDRESS_TYPE_TWOBYTES == addressType - * e | children address, 2 bytes - * s | ELSE // 11 = FLAG_CHILDREN_ADDRESS_TYPE_THREEBYTES = addressType - * s | children address, 3 bytes - * | END - * | This address is relative to the position of this field. + * c | + * h | children address, 3 bytes + * i | 1 byte = bbbbbbbb match + * l | case 1xxxxxxx => -((0xxxxxxx << 16) + (next byte << 8) + next byte) + * d | otherwise => (bbbbbbbb<<16) + (next byte << 8) + next byte + * r | if this node doesn't have children, this field is set to 0. + * e | (see BinaryDictEncoderUtils#writeVariableSignedAddress) + * n | This address is relative to the position of this field. + * a | + * ddress * * | IF FLAG_IS_TERMINAL && FLAG_HAS_SHORTCUT_TARGETS * | shortcut string list @@ -208,17 +188,12 @@ public final class FormatSpec { // us to change the format during development while having testing devices remove // older files with each upgrade, while still having a readable versioning scheme. public static final int VERSION2 = 2; - public static final int VERSION3 = 3; public static final int VERSION4 = 400; static final int MINIMUM_SUPPORTED_VERSION = VERSION2; static final int MAXIMUM_SUPPORTED_VERSION = VERSION4; // These options need to be the same numeric values as the one in the native reading code. - static final int GERMAN_UMLAUT_PROCESSING_FLAG = 0x1; // TODO: Make the native reading code read this variable. - static final int SUPPORTS_DYNAMIC_UPDATE = 0x2; - static final int FRENCH_LIGATURE_PROCESSING_FLAG = 0x4; - static final int CONTAINS_BIGRAMS_FLAG = 0x8; static final int CONTAINS_TIMESTAMP_FLAG = 0x10; // TODO: Make this value adaptative to content data, store it in the header, and @@ -339,30 +314,23 @@ public final class FormatSpec { */ public static final class FormatOptions { public final int mVersion; - public final boolean mSupportsDynamicUpdate; public final boolean mHasTerminalId; public final boolean mHasTimestamp; - @UsedForTesting - public FormatOptions(final int version) { - this(version, false); - } @UsedForTesting - public FormatOptions(final int version, final boolean supportsDynamicUpdate) { - this(version, supportsDynamicUpdate, false /* hasTimestamp */); + public FormatOptions(final int version) { + this(version, false /* hasTimestamp */); } - public FormatOptions(final int version, final boolean supportsDynamicUpdate, - final boolean hasTimestamp) { + public FormatOptions(final int version, final boolean hasTimestamp) { mVersion = version; - if (version < FIRST_VERSION_WITH_DYNAMIC_UPDATE && supportsDynamicUpdate) { - throw new RuntimeException("Dynamic updates are only supported with versions " - + FIRST_VERSION_WITH_DYNAMIC_UPDATE + " and ulterior."); - } - mSupportsDynamicUpdate = supportsDynamicUpdate; mHasTerminalId = (version >= FIRST_VERSION_WITH_TERMINAL_ID); mHasTimestamp = hasTimestamp; } + + public boolean supportsDynamicUpdate() { + return mVersion >= FIRST_VERSION_WITH_DYNAMIC_UPDATE; + } } /** @@ -374,7 +342,6 @@ public final class FormatSpec { public final FormatOptions mFormatOptions; // Note that these are corresponding definitions in native code in latinime::HeaderPolicy // and latinime::HeaderReadWriteUtils. - public static final String SUPPORTS_DYNAMIC_UPDATE_ATTRIBUTE = "SUPPORTS_DYNAMIC_UPDATE"; public static final String USES_FORGETTING_CURVE_ATTRIBUTE = "USES_FORGETTING_CURVE"; public static final String HAS_HISTORICAL_INFO_ATTRIBUTE = "HAS_HISTORICAL_INFO"; public static final String ATTRIBUTE_VALUE_TRUE = "1"; @@ -433,7 +400,7 @@ public final class FormatSpec { if (dictFile.isDirectory()) { return new Ver4DictDecoder(dictFile, bufferType); } else if (dictFile.isFile()) { - return new Ver3DictDecoder(dictFile, bufferType); + return new Ver2DictDecoder(dictFile, bufferType); } return null; } @@ -443,7 +410,7 @@ public final class FormatSpec { if (dictFile.isDirectory()) { return new Ver4DictDecoder(dictFile, factory); } else if (dictFile.isFile()) { - return new Ver3DictDecoder(dictFile, factory); + return new Ver2DictDecoder(dictFile, factory); } return null; } diff --git a/java/src/com/android/inputmethod/latin/makedict/FusionDictionary.java b/java/src/com/android/inputmethod/latin/makedict/FusionDictionary.java index 3bb218bea..fdf2ae7b5 100644 --- a/java/src/com/android/inputmethod/latin/makedict/FusionDictionary.java +++ b/java/src/com/android/inputmethod/latin/makedict/FusionDictionary.java @@ -303,14 +303,9 @@ public final class FusionDictionary implements Iterable<Word> { * Options global to the dictionary. */ public static final class DictionaryOptions { - public final boolean mGermanUmlautProcessing; - public final boolean mFrenchLigatureProcessing; public final HashMap<String, String> mAttributes; - public DictionaryOptions(final HashMap<String, String> attributes, - final boolean germanUmlautProcessing, final boolean frenchLigatureProcessing) { + public DictionaryOptions(final HashMap<String, String> attributes) { mAttributes = attributes; - mGermanUmlautProcessing = germanUmlautProcessing; - mFrenchLigatureProcessing = frenchLigatureProcessing; } @Override public String toString() { // Convenience method @@ -339,14 +334,6 @@ public final class FusionDictionary implements Iterable<Word> { } s.append("\n"); } - if (mGermanUmlautProcessing) { - s.append(indent); - s.append("Needs German umlaut processing\n"); - } - if (mFrenchLigatureProcessing) { - s.append(indent); - s.append("Needs French ligature processing\n"); - } return s.toString(); } } @@ -701,138 +688,6 @@ public final class FusionDictionary implements Iterable<Word> { } /** - * Recursively count the number of nodes in a given branch of the trie. - * - * @param nodeArray the node array to count. - * @return the number of nodes in this branch. - */ - public static int countNodeArrays(final PtNodeArray nodeArray) { - int size = 1; - for (int i = nodeArray.mData.size() - 1; i >= 0; --i) { - PtNode ptNode = nodeArray.mData.get(i); - if (null != ptNode.mChildren) - size += countNodeArrays(ptNode.mChildren); - } - return size; - } - - // Recursively find out whether there are any bigrams. - // This can be pretty expensive especially if there aren't any (we return as soon - // as we find one, so it's much cheaper if there are bigrams) - private static boolean hasBigramsInternal(final PtNodeArray nodeArray) { - if (null == nodeArray) return false; - for (int i = nodeArray.mData.size() - 1; i >= 0; --i) { - PtNode ptNode = nodeArray.mData.get(i); - if (null != ptNode.mBigrams) return true; - if (hasBigramsInternal(ptNode.mChildren)) return true; - } - return false; - } - - /** - * Finds out whether there are any bigrams in this dictionary. - * - * @return true if there is any bigram, false otherwise. - */ - // TODO: this is expensive especially for large dictionaries without any bigram. - // The up side is, this is always accurate and correct and uses no memory. We should - // find a more efficient way of doing this, without compromising too much on memory - // and ease of use. - public boolean hasBigrams() { - return hasBigramsInternal(mRootNodeArray); - } - - // Historically, the tails of the words were going to be merged to save space. - // However, that would prevent the code to search for a specific address in log(n) - // time so this was abandoned. - // The code is still of interest as it does add some compression to any dictionary - // that has no need for attributes. Implementations that does not read attributes should be - // able to read a dictionary with merged tails. - // Also, the following code does support frequencies, as in, it will only merges - // tails that share the same frequency. Though it would result in the above loss of - // performance while searching by address, it is still technically possible to merge - // tails that contain attributes, but this code does not take that into account - it does - // not compare attributes and will merge terminals with different attributes regardless. - public void mergeTails() { - MakedictLog.i("Do not merge tails"); - return; - -// MakedictLog.i("Merging PtNodes. Number of PtNodes : " + countPtNodes(root)); -// MakedictLog.i("Number of PtNodes : " + countPtNodes(root)); -// -// final HashMap<String, ArrayList<PtNodeArray>> repository = -// new HashMap<String, ArrayList<PtNodeArray>>(); -// mergeTailsInner(repository, root); -// -// MakedictLog.i("Number of different pseudohashes : " + repository.size()); -// int size = 0; -// for (ArrayList<PtNodeArray> a : repository.values()) { -// size += a.size(); -// } -// MakedictLog.i("Number of nodes after merge : " + (1 + size)); -// MakedictLog.i("Recursively seen nodes : " + countNodes(root)); - } - - // The following methods are used by the deactivated mergeTails() -// private static boolean isEqual(PtNodeArray a, PtNodeArray b) { -// if (null == a && null == b) return true; -// if (null == a || null == b) return false; -// if (a.data.size() != b.data.size()) return false; -// final int size = a.data.size(); -// for (int i = size - 1; i >= 0; --i) { -// PtNode aPtNode = a.data.get(i); -// PtNode bPtNode = b.data.get(i); -// if (aPtNode.frequency != bPtNode.frequency) return false; -// if (aPtNode.alternates == null && bPtNode.alternates != null) return false; -// if (aPtNode.alternates != null && !aPtNode.equals(bPtNode.alternates)) return false; -// if (!Arrays.equals(aPtNode.chars, bPtNode.chars)) return false; -// if (!isEqual(aPtNode.children, bPtNode.children)) return false; -// } -// return true; -// } - -// static private HashMap<String, ArrayList<PtNodeArray>> mergeTailsInner( -// final HashMap<String, ArrayList<PtNodeArray>> map, final PtNodeArray nodeArray) { -// final ArrayList<PtNode> branches = nodeArray.data; -// final int nodeSize = branches.size(); -// for (int i = 0; i < nodeSize; ++i) { -// PtNode ptNode = branches.get(i); -// if (null != ptNode.children) { -// String pseudoHash = getPseudoHash(ptNode.children); -// ArrayList<PtNodeArray> similarList = map.get(pseudoHash); -// if (null == similarList) { -// similarList = new ArrayList<PtNodeArray>(); -// map.put(pseudoHash, similarList); -// } -// boolean merged = false; -// for (PtNodeArray similar : similarList) { -// if (isEqual(ptNode.children, similar)) { -// ptNode.children = similar; -// merged = true; -// break; -// } -// } -// if (!merged) { -// similarList.add(ptNode.children); -// } -// mergeTailsInner(map, ptNode.children); -// } -// } -// return map; -// } - -// private static String getPseudoHash(final PtNodeArray nodeArray) { -// StringBuilder s = new StringBuilder(); -// for (PtNode ptNode : nodeArray.data) { -// s.append(ptNode.frequency); -// for (int ch : ptNode.chars) { -// s.append(Character.toChars(ch)); -// } -// } -// return s.toString(); -// } - - /** * Iterator to walk through a dictionary. * * This is purely for convenience. diff --git a/java/src/com/android/inputmethod/latin/makedict/Ver3DictDecoder.java b/java/src/com/android/inputmethod/latin/makedict/Ver2DictDecoder.java index acab4f8a5..e9667ab0b 100644 --- a/java/src/com/android/inputmethod/latin/makedict/Ver3DictDecoder.java +++ b/java/src/com/android/inputmethod/latin/makedict/Ver2DictDecoder.java @@ -34,18 +34,11 @@ import java.util.ArrayList; import java.util.Arrays; /** - * An implementation of DictDecoder for version 3 binary dictionary. + * An implementation of DictDecoder for version 2 binary dictionary. */ @UsedForTesting -public class Ver3DictDecoder extends AbstractDictDecoder { - private static final String TAG = Ver3DictDecoder.class.getSimpleName(); - - static { - JniUtils.loadNativeLibrary(); - } - - // TODO: implement something sensical instead of just a phony method - private static native int doNothing(); +public class Ver2DictDecoder extends AbstractDictDecoder { + private static final String TAG = Ver2DictDecoder.class.getSimpleName(); protected static class PtNodeReader extends AbstractDictDecoder.PtNodeReader { private static int readFrequency(final DictBuffer dictBuffer) { @@ -57,7 +50,7 @@ public class Ver3DictDecoder extends AbstractDictDecoder { private final DictionaryBufferFactory mBufferFactory; protected DictBuffer mDictBuffer; - /* package */ Ver3DictDecoder(final File file, final int factoryFlag) { + /* package */ Ver2DictDecoder(final File file, final int factoryFlag) { mDictionaryBinaryFile = file; mDictBuffer = null; @@ -72,7 +65,7 @@ public class Ver3DictDecoder extends AbstractDictDecoder { } } - /* package */ Ver3DictDecoder(final File file, final DictionaryBufferFactory factory) { + /* package */ Ver2DictDecoder(final File file, final DictionaryBufferFactory factory) { mDictionaryBinaryFile = file; mBufferFactory = factory; } @@ -166,7 +159,7 @@ public class Ver3DictDecoder extends AbstractDictDecoder { final ArrayList<PendingAttribute> bigrams; if (0 != (flags & FormatSpec.FLAG_HAS_BIGRAMS)) { bigrams = new ArrayList<PendingAttribute>(); - addressPointer += PtNodeReader.readBigramAddresses(mDictBuffer, bigrams, + addressPointer += PtNodeReader.readBigramAddresses(mDictBuffer, bigrams, addressPointer); if (bigrams.size() >= FormatSpec.MAX_BIGRAMS_IN_A_PTNODE) { throw new RuntimeException("Too many bigrams in a PtNode (" + bigrams.size() diff --git a/java/src/com/android/inputmethod/latin/makedict/Ver3DictEncoder.java b/java/src/com/android/inputmethod/latin/makedict/Ver2DictEncoder.java index 5da34534e..e5430423d 100644 --- a/java/src/com/android/inputmethod/latin/makedict/Ver3DictEncoder.java +++ b/java/src/com/android/inputmethod/latin/makedict/Ver2DictEncoder.java @@ -31,16 +31,16 @@ import java.util.ArrayList; import java.util.Iterator; /** - * An implementation of DictEncoder for version 3 binary dictionary. + * An implementation of DictEncoder for version 2 binary dictionary. */ -public class Ver3DictEncoder implements DictEncoder { +public class Ver2DictEncoder implements DictEncoder { private final File mDictFile; private OutputStream mOutStream; private byte[] mBuffer; private int mPosition; - public Ver3DictEncoder(final File dictFile) { + public Ver2DictEncoder(final File dictFile) { mDictFile = dictFile; mOutStream = null; mBuffer = null; @@ -49,7 +49,7 @@ public class Ver3DictEncoder implements DictEncoder { // This constructor is used only by BinaryDictOffdeviceUtilsTests. // If you want to use this in the production code, you should consider keeping consistency of // the interface of Ver3DictDecoder by using factory. - public Ver3DictEncoder(final OutputStream outStream) { + public Ver2DictEncoder(final OutputStream outStream) { mDictFile = null; mOutStream = outStream; } @@ -68,7 +68,7 @@ public class Ver3DictEncoder implements DictEncoder { @Override public void writeDictionary(final FusionDictionary dict, final FormatOptions formatOptions) throws IOException, UnsupportedFormatException { - if (formatOptions.mVersion > FormatSpec.VERSION3) { + if (formatOptions.mVersion > FormatSpec.VERSION2) { throw new UnsupportedFormatException( "The given format options has wrong version number : " + formatOptions.mVersion); @@ -169,7 +169,7 @@ public class Ver3DictEncoder implements DictEncoder { private void writeChildrenPosition(final PtNode ptNode, final FormatOptions formatOptions) { final int childrenPos = BinaryDictEncoderUtils.getChildrenPosition(ptNode, formatOptions); - if (formatOptions.mSupportsDynamicUpdate) { + if (formatOptions.supportsDynamicUpdate()) { mPosition += BinaryDictEncoderUtils.writeSignedChildrenPosition(mBuffer, mPosition, childrenPos); } else { diff --git a/java/src/com/android/inputmethod/latin/makedict/Ver3DictUpdater.java b/java/src/com/android/inputmethod/latin/makedict/Ver3DictUpdater.java deleted file mode 100644 index 07adda625..000000000 --- a/java/src/com/android/inputmethod/latin/makedict/Ver3DictUpdater.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (C) 2013 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.makedict; - -import com.android.inputmethod.annotations.UsedForTesting; -import com.android.inputmethod.latin.makedict.FusionDictionary.WeightedString; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.util.ArrayList; - -/** - * An implementation of DictUpdater for version 3 binary dictionary. - */ -@UsedForTesting -public class Ver3DictUpdater extends Ver3DictDecoder implements DictUpdater { - private OutputStream mOutStream; - - @UsedForTesting - public Ver3DictUpdater(final File dictFile, final int factoryType) { - // DictUpdater must have an updatable DictBuffer. - super(dictFile, ((factoryType & MASK_DICTBUFFER) == USE_BYTEARRAY) - ? USE_BYTEARRAY : USE_WRITABLE_BYTEBUFFER); - mOutStream = null; - } - - private void openStreamAndBuffer() throws FileNotFoundException, IOException { - super.openDictBuffer(); - mOutStream = new FileOutputStream(mDictionaryBinaryFile, true /* append */); - } - - private void close() throws IOException { - if (mOutStream != null) { - mOutStream.close(); - mOutStream = null; - } - } - - @Override @UsedForTesting - public void deleteWord(final String word) throws IOException, UnsupportedFormatException { - if (mOutStream == null) openStreamAndBuffer(); - mDictBuffer.position(0); - readHeader(); - final int wordPos = getTerminalPosition(word); - if (wordPos != FormatSpec.NOT_VALID_WORD) { - mDictBuffer.position(wordPos); - final int flags = mDictBuffer.readUnsignedByte(); - mDictBuffer.position(wordPos); - mDictBuffer.put((byte) DynamicBinaryDictIOUtils.markAsDeleted(flags)); - } - close(); - } - - @Override @UsedForTesting - public void insertWord(final String word, final int frequency, - final ArrayList<WeightedString> bigramStrings, - final ArrayList<WeightedString> shortcuts, - final boolean isNotAWord, final boolean isBlackListEntry) - throws IOException, UnsupportedFormatException { - if (mOutStream == null) openStreamAndBuffer(); - DynamicBinaryDictIOUtils.insertWord(this, mOutStream, word, frequency, bigramStrings, - shortcuts, isNotAWord, isBlackListEntry); - close(); - } -} diff --git a/java/src/com/android/inputmethod/latin/makedict/Ver4DictDecoder.java b/java/src/com/android/inputmethod/latin/makedict/Ver4DictDecoder.java index 07522b54b..3be62f066 100644 --- a/java/src/com/android/inputmethod/latin/makedict/Ver4DictDecoder.java +++ b/java/src/com/android/inputmethod/latin/makedict/Ver4DictDecoder.java @@ -183,14 +183,11 @@ public class Ver4DictDecoder extends AbstractDictDecoder { * An auxiliary class for reading bigrams. */ protected static class BigramContentReader extends SparseTableContentReader { - private final boolean mHasTimestamp; - public BigramContentReader(final String name, final File baseDir, final DictionaryBufferFactory factory, final boolean hasTimestamp) { super(name + FormatSpec.BIGRAM_FILE_EXTENSION, FormatSpec.BIGRAM_ADDRESS_TABLE_BLOCK_SIZE, baseDir, getContentFilenames(name, hasTimestamp), getContentIds(hasTimestamp), factory); - mHasTimestamp = hasTimestamp; } // TODO: Consolidate this method and BigramContentWriter.getContentFilenames. diff --git a/java/src/com/android/inputmethod/latin/makedict/Ver4DictEncoder.java b/java/src/com/android/inputmethod/latin/makedict/Ver4DictEncoder.java index 1a245b6db..8eaee4d9f 100644 --- a/java/src/com/android/inputmethod/latin/makedict/Ver4DictEncoder.java +++ b/java/src/com/android/inputmethod/latin/makedict/Ver4DictEncoder.java @@ -1,5 +1,4 @@ /* -/* * Copyright (C) 2013 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,25 +17,15 @@ package com.android.inputmethod.latin.makedict; import com.android.inputmethod.annotations.UsedForTesting; -import com.android.inputmethod.latin.makedict.BinaryDictDecoderUtils.CharEncoding; -import com.android.inputmethod.latin.makedict.FormatSpec.FileHeader; +import com.android.inputmethod.latin.BinaryDictionary; +import com.android.inputmethod.latin.Dictionary; import com.android.inputmethod.latin.makedict.FormatSpec.FormatOptions; -import com.android.inputmethod.latin.makedict.FusionDictionary.DictionaryOptions; import com.android.inputmethod.latin.makedict.FusionDictionary.PtNode; -import com.android.inputmethod.latin.makedict.FusionDictionary.PtNodeArray; import com.android.inputmethod.latin.makedict.FusionDictionary.WeightedString; -import com.android.inputmethod.latin.utils.CollectionUtils; -import com.android.inputmethod.latin.utils.FileUtils; +import com.android.inputmethod.latin.utils.LocaleUtils; import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; import java.io.IOException; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.Iterator; /** * An implementation of DictEncoder for version 4 binary dictionary. @@ -44,197 +33,19 @@ import java.util.Iterator; @UsedForTesting public class Ver4DictEncoder implements DictEncoder { private final File mDictPlacedDir; - private byte[] mTrieBuf; - private int mTriePos; - private OutputStream mTrieOutStream; - private OutputStream mHeaderOutStream; - private OutputStream mFreqOutStream; - private OutputStream mUnigramTimestampOutStream; - private OutputStream mTerminalAddressTableOutStream; - private File mDictDir; - private String mBaseFilename; - private BigramContentWriter mBigramWriter; - private ShortcutContentWriter mShortcutWriter; @UsedForTesting public Ver4DictEncoder(final File dictPlacedDir) { mDictPlacedDir = dictPlacedDir; } - private static class BigramContentWriter extends SparseTableContentWriter { - private final boolean mWriteTimestamp; - - public BigramContentWriter(final String name, final int initialCapacity, - final File baseDir, final boolean writeTimestamp) { - super(name + FormatSpec.BIGRAM_FILE_EXTENSION, initialCapacity, - FormatSpec.BIGRAM_ADDRESS_TABLE_BLOCK_SIZE, baseDir, - getContentFilenames(name, writeTimestamp), getContentIds(writeTimestamp)); - mWriteTimestamp = writeTimestamp; - } - - private static String[] getContentFilenames(final String name, - final boolean writeTimestamp) { - final String[] contentFilenames; - if (writeTimestamp) { - contentFilenames = new String[] { name + FormatSpec.BIGRAM_FILE_EXTENSION, - name + FormatSpec.BIGRAM_FILE_EXTENSION }; - } else { - contentFilenames = new String[] { name + FormatSpec.BIGRAM_FILE_EXTENSION }; - } - return contentFilenames; - } - - private static String[] getContentIds(final boolean writeTimestamp) { - final String[] contentIds; - if (writeTimestamp) { - contentIds = new String[] { FormatSpec.BIGRAM_FREQ_CONTENT_ID, - FormatSpec.BIGRAM_TIMESTAMP_CONTENT_ID }; - } else { - contentIds = new String[] { FormatSpec.BIGRAM_FREQ_CONTENT_ID }; - } - return contentIds; - } - - public void writeBigramsForOneWord(final int terminalId, final int bigramCount, - final Iterator<WeightedString> bigramIterator, final FusionDictionary dict) - throws IOException { - write(FormatSpec.BIGRAM_FREQ_CONTENT_INDEX, terminalId, - new SparseTableContentWriterInterface() { - @Override - public void write(final OutputStream outStream) throws IOException { - writeBigramsForOneWordInternal(outStream, bigramIterator, dict); - }}); - if (mWriteTimestamp) { - write(FormatSpec.BIGRAM_TIMESTAMP_CONTENT_INDEX, terminalId, - new SparseTableContentWriterInterface() { - @Override - public void write(final OutputStream outStream) throws IOException { - initBigramTimestampsCountersAndLevelsForOneWordInternal(outStream, - bigramCount); - }}); - } - } - - private void writeBigramsForOneWordInternal(final OutputStream outStream, - final Iterator<WeightedString> bigramIterator, final FusionDictionary dict) - throws IOException { - while (bigramIterator.hasNext()) { - final WeightedString bigram = bigramIterator.next(); - final PtNode target = - FusionDictionary.findWordInTree(dict.mRootNodeArray, bigram.mWord); - final int unigramFrequencyForThisWord = target.mFrequency; - final int bigramFlags = BinaryDictEncoderUtils.makeBigramFlags( - bigramIterator.hasNext(), 0, bigram.mFrequency, - unigramFrequencyForThisWord, bigram.mWord); - BinaryDictEncoderUtils.writeUIntToStream(outStream, bigramFlags, - FormatSpec.PTNODE_ATTRIBUTE_FLAGS_SIZE); - BinaryDictEncoderUtils.writeUIntToStream(outStream, target.mTerminalId, - FormatSpec.PTNODE_ATTRIBUTE_MAX_ADDRESS_SIZE); - } - } - - private void initBigramTimestampsCountersAndLevelsForOneWordInternal( - final OutputStream outStream, final int bigramCount) throws IOException { - for (int i = 0; i < bigramCount; ++i) { - // TODO: Figure out what initial values should be. - BinaryDictEncoderUtils.writeUIntToStream(outStream, 0 /* value */, - FormatSpec.BIGRAM_TIMESTAMP_SIZE); - BinaryDictEncoderUtils.writeUIntToStream(outStream, 0 /* value */, - FormatSpec.BIGRAM_COUNTER_SIZE); - BinaryDictEncoderUtils.writeUIntToStream(outStream, 0 /* value */, - FormatSpec.BIGRAM_LEVEL_SIZE); - } - } - } - - private static class ShortcutContentWriter extends SparseTableContentWriter { - public ShortcutContentWriter(final String name, final int initialCapacity, - final File baseDir) { - super(name + FormatSpec.SHORTCUT_FILE_EXTENSION, initialCapacity, - FormatSpec.SHORTCUT_ADDRESS_TABLE_BLOCK_SIZE, baseDir, - new String[] { name + FormatSpec.SHORTCUT_FILE_EXTENSION }, - new String[] { FormatSpec.SHORTCUT_CONTENT_ID }); - } - - public void writeShortcutForOneWord(final int terminalId, - final Iterator<WeightedString> shortcutIterator) throws IOException { - write(FormatSpec.SHORTCUT_CONTENT_INDEX, terminalId, - new SparseTableContentWriterInterface() { - @Override - public void write(final OutputStream outStream) throws IOException { - writeShortcutForOneWordInternal(outStream, shortcutIterator); - } - }); - } - - private void writeShortcutForOneWordInternal(final OutputStream outStream, - final Iterator<WeightedString> shortcutIterator) throws IOException { - while (shortcutIterator.hasNext()) { - final WeightedString target = shortcutIterator.next(); - final int shortcutFlags = BinaryDictEncoderUtils.makeShortcutFlags( - shortcutIterator.hasNext(), target.mFrequency); - BinaryDictEncoderUtils.writeUIntToStream(outStream, shortcutFlags, - FormatSpec.PTNODE_ATTRIBUTE_FLAGS_SIZE); - CharEncoding.writeString(outStream, target.mWord); - } - } - } - - private void openStreams(final FormatOptions formatOptions, final DictionaryOptions dictOptions) - throws FileNotFoundException, IOException { - final FileHeader header = new FileHeader(0, dictOptions, formatOptions); - mBaseFilename = header.getId() + "." + header.getVersion(); - mDictDir = new File(mDictPlacedDir, mBaseFilename); - final File trieFile = new File(mDictDir, mBaseFilename + FormatSpec.TRIE_FILE_EXTENSION); - final File headerFile = new File(mDictDir, - mBaseFilename + FormatSpec.HEADER_FILE_EXTENSION); - final File freqFile = new File(mDictDir, mBaseFilename + FormatSpec.FREQ_FILE_EXTENSION); - final File timestampFile = new File(mDictDir, - mBaseFilename + FormatSpec.UNIGRAM_TIMESTAMP_FILE_EXTENSION); - final File terminalAddressTableFile = new File(mDictDir, - mBaseFilename + FormatSpec.TERMINAL_ADDRESS_TABLE_FILE_EXTENSION); - if (!mDictDir.isDirectory()) { - if (mDictDir.exists()) { - FileUtils.deleteRecursively(mDictDir); - } - mDictDir.mkdirs(); - } - mTrieOutStream = new FileOutputStream(trieFile); - mHeaderOutStream = new FileOutputStream(headerFile); - mFreqOutStream = new FileOutputStream(freqFile); - mTerminalAddressTableOutStream = new FileOutputStream(terminalAddressTableFile); - if (formatOptions.mHasTimestamp) { - mUnigramTimestampOutStream = new FileOutputStream(timestampFile); - } - } - - private void close() throws IOException { - try { - if (mTrieOutStream != null) { - mTrieOutStream.close(); - } - if (mHeaderOutStream != null) { - mHeaderOutStream.close(); - } - if (mFreqOutStream != null) { - mFreqOutStream.close(); - } - if (mTerminalAddressTableOutStream != null) { - mTerminalAddressTableOutStream.close(); - } - if (mUnigramTimestampOutStream != null) { - mUnigramTimestampOutStream.close(); - } - } finally { - mTrieOutStream = null; - mHeaderOutStream = null; - mFreqOutStream = null; - mTerminalAddressTableOutStream = null; - } - } - + // TODO: This builds a FusionDictionary first and iterates it to add words to the binary + // dictionary. However, it is possible to just add words directly to the binary dictionary + // instead. + // In the long run, when we stop supporting version 2, FusionDictionary will become deprecated + // and we can remove it. Then we'll be able to just call BinaryDictionary directly. @Override - public void writeDictionary(final FusionDictionary dict, final FormatOptions formatOptions) + public void writeDictionary(FusionDictionary dict, FormatOptions formatOptions) throws IOException, UnsupportedFormatException { if (formatOptions.mVersion != FormatSpec.VERSION4) { throw new UnsupportedFormatException("File header has a wrong version number : " @@ -243,208 +54,71 @@ public class Ver4DictEncoder implements DictEncoder { if (!mDictPlacedDir.isDirectory()) { throw new UnsupportedFormatException("Given path is not a directory."); } - - if (mTrieOutStream == null) { - openStreams(formatOptions, dict.mOptions); - } - - BinaryDictEncoderUtils.writeDictionaryHeader(mHeaderOutStream, dict, formatOptions); - - MakedictLog.i("Flattening the tree..."); - ArrayList<PtNodeArray> flatNodes = BinaryDictEncoderUtils.flattenTree(dict.mRootNodeArray); - int terminalCount = 0; - final ArrayList<PtNode> nodes = CollectionUtils.newArrayList(); - for (final PtNodeArray array : flatNodes) { - for (final PtNode node : array.mData) { - if (node.isTerminal()) { - nodes.add(node); - node.mTerminalId = terminalCount++; + if (!BinaryDictionary.createEmptyDictFile(mDictPlacedDir.getAbsolutePath(), + FormatSpec.VERSION4, dict.mOptions.mAttributes)) { + throw new IOException("Cannot create dictionary file : " + + mDictPlacedDir.getAbsolutePath()); + } + final BinaryDictionary binaryDict = new BinaryDictionary(mDictPlacedDir.getAbsolutePath(), + 0l, mDictPlacedDir.length(), true /* useFullEditDistance */, + LocaleUtils.constructLocaleFromString(dict.mOptions.mAttributes.get( + FormatSpec.FileHeader.DICTIONARY_LOCALE_ATTRIBUTE)), + Dictionary.TYPE_USER /* Dictionary type. Does not matter for us */, + true /* isUpdatable */); + if (!binaryDict.isValidDictionary()) { + // Somehow createEmptyDictFile returned true, but the file was not created correctly + throw new IOException("Cannot create dictionary file"); + } + for (final Word word : dict) { + // TODO: switch to addMultipleDictionaryEntries when they support shortcuts + if (null == word.mShortcutTargets || word.mShortcutTargets.isEmpty()) { + binaryDict.addUnigramWord(word.mWord, word.mFrequency, + null /* shortcutTarget */, 0 /* shortcutProbability */, + word.mIsNotAWord, word.mIsBlacklistEntry, 0 /* timestamp */); + } else { + for (final WeightedString shortcutTarget : word.mShortcutTargets) { + binaryDict.addUnigramWord(word.mWord, word.mFrequency, + shortcutTarget.mWord, shortcutTarget.mFrequency, + word.mIsNotAWord, word.mIsBlacklistEntry, 0 /* timestamp */); } } - } - Collections.sort(nodes, new Comparator<PtNode>() { - @Override - public int compare(final PtNode lhs, final PtNode rhs) { - if (lhs.mFrequency != rhs.mFrequency) { - return lhs.mFrequency < rhs.mFrequency ? -1 : 1; - } - if (lhs.mTerminalId < rhs.mTerminalId) return -1; - if (lhs.mTerminalId > rhs.mTerminalId) return 1; - return 0; + if (binaryDict.needsToRunGC(true /* mindsBlockByGC */)) { + binaryDict.flushWithGC(); } - }); - int count = 0; - for (final PtNode node : nodes) { - node.mTerminalId = count++; - } - - MakedictLog.i("Computing addresses..."); - BinaryDictEncoderUtils.computeAddresses(dict, flatNodes, formatOptions); - if (MakedictLog.DBG) BinaryDictEncoderUtils.checkFlatPtNodeArrayList(flatNodes); - - writeTerminalData(flatNodes, terminalCount); - if (formatOptions.mHasTimestamp) { - initUnigramTimestamps(terminalCount); - } - mBigramWriter = new BigramContentWriter(mBaseFilename, terminalCount, mDictDir, - formatOptions.mHasTimestamp); - writeBigrams(flatNodes, dict); - mShortcutWriter = new ShortcutContentWriter(mBaseFilename, terminalCount, mDictDir); - writeShortcuts(flatNodes); - - final PtNodeArray lastNodeArray = flatNodes.get(flatNodes.size() - 1); - final int bufferSize = lastNodeArray.mCachedAddressAfterUpdate + lastNodeArray.mCachedSize; - mTrieBuf = new byte[bufferSize]; - - MakedictLog.i("Writing file..."); - for (PtNodeArray nodeArray : flatNodes) { - BinaryDictEncoderUtils.writePlacedPtNodeArray(dict, this, nodeArray, formatOptions); } - if (MakedictLog.DBG) { - BinaryDictEncoderUtils.showStatistics(flatNodes); - MakedictLog.i("has " + terminalCount + " terminals."); + for (final Word word0 : dict) { + if (null == word0.mBigrams) continue; + for (final WeightedString word1 : word0.mBigrams) { + binaryDict.addBigramWords(word0.mWord, word1.mWord, word1.mFrequency, + 0 /* timestamp */); + } + if (binaryDict.needsToRunGC(true /* mindsBlockByGC */)) { + binaryDict.flushWithGC(); + } } - mTrieOutStream.write(mTrieBuf); - - MakedictLog.i("Done"); - close(); + binaryDict.flushWithGC(); + binaryDict.close(); } @Override public void setPosition(int position) { - if (mTrieBuf == null || position < 0 || position > mTrieBuf.length) return; - mTriePos = position; } @Override public int getPosition() { - return mTriePos; + return 0; } @Override public void writePtNodeCount(int ptNodeCount) { - final int countSize = BinaryDictIOUtils.getPtNodeCountSize(ptNodeCount); - // ptNodeCount must fit on one byte or two bytes. - // Please see comments in FormatSpec - if (countSize != 1 && countSize != 2) { - throw new RuntimeException("Strange size from getPtNodeCountSize : " + countSize); - } - final int encodedPtNodeCount = (countSize == 2) ? - (ptNodeCount | FormatSpec.LARGE_PTNODE_ARRAY_SIZE_FIELD_SIZE_FLAG) : ptNodeCount; - mTriePos = BinaryDictEncoderUtils.writeUIntToBuffer(mTrieBuf, mTriePos, encodedPtNodeCount, - countSize); - } - - private void writePtNodeFlags(final PtNode ptNode, final FormatOptions formatOptions) { - final int childrenPos = BinaryDictEncoderUtils.getChildrenPosition(ptNode, formatOptions); - mTriePos = BinaryDictEncoderUtils.writeUIntToBuffer(mTrieBuf, mTriePos, - BinaryDictEncoderUtils.makePtNodeFlags(ptNode, childrenPos, formatOptions), - FormatSpec.PTNODE_FLAGS_SIZE); - } - - private void writeParentPosition(int parentPos, final PtNode ptNode, - final FormatOptions formatOptions) { - if (parentPos != FormatSpec.NO_PARENT_ADDRESS) { - parentPos -= ptNode.mCachedAddressAfterUpdate; - } - mTriePos = BinaryDictEncoderUtils.writeParentAddress(mTrieBuf, mTriePos, parentPos, - formatOptions); - } - - private void writeCharacters(final int[] characters, final boolean hasSeveralChars) { - mTriePos = CharEncoding.writeCharArray(characters, mTrieBuf, mTriePos); - if (hasSeveralChars) { - mTrieBuf[mTriePos++] = FormatSpec.PTNODE_CHARACTERS_TERMINATOR; - } - } - - private void writeTerminalId(final int terminalId) { - mTriePos = BinaryDictEncoderUtils.writeUIntToBuffer(mTrieBuf, mTriePos, terminalId, - FormatSpec.PTNODE_TERMINAL_ID_SIZE); - } - - private void writeChildrenPosition(PtNode ptNode, FormatOptions formatOptions) { - final int childrenPos = BinaryDictEncoderUtils.getChildrenPosition(ptNode, formatOptions); - if (formatOptions.mSupportsDynamicUpdate) { - mTriePos += BinaryDictEncoderUtils.writeSignedChildrenPosition(mTrieBuf, - mTriePos, childrenPos); - } else { - mTriePos += BinaryDictEncoderUtils.writeChildrenPosition(mTrieBuf, - mTriePos, childrenPos); - } - } - - private void writeBigrams(final ArrayList<PtNodeArray> flatNodes, final FusionDictionary dict) - throws IOException { - mBigramWriter.openStreams(); - for (final PtNodeArray nodeArray : flatNodes) { - for (final PtNode ptNode : nodeArray.mData) { - if (ptNode.mBigrams != null) { - mBigramWriter.writeBigramsForOneWord(ptNode.mTerminalId, ptNode.mBigrams.size(), - ptNode.mBigrams.iterator(), dict); - } - } - } - mBigramWriter.closeStreams(); - } - - private void writeShortcuts(final ArrayList<PtNodeArray> flatNodes) throws IOException { - mShortcutWriter.openStreams(); - for (final PtNodeArray nodeArray : flatNodes) { - for (final PtNode ptNode : nodeArray.mData) { - if (ptNode.mShortcutTargets != null && !ptNode.mShortcutTargets.isEmpty()) { - mShortcutWriter.writeShortcutForOneWord(ptNode.mTerminalId, - ptNode.mShortcutTargets.iterator()); - } - } - } - mShortcutWriter.closeStreams(); } @Override public void writeForwardLinkAddress(int forwardLinkAddress) { - mTriePos = BinaryDictEncoderUtils.writeUIntToBuffer(mTrieBuf, mTriePos, - forwardLinkAddress, FormatSpec.FORWARD_LINK_ADDRESS_SIZE); } @Override - public void writePtNode(final PtNode ptNode, final int parentPosition, - final FormatOptions formatOptions, final FusionDictionary dict) { - writePtNodeFlags(ptNode, formatOptions); - writeParentPosition(parentPosition, ptNode, formatOptions); - writeCharacters(ptNode.mChars, ptNode.hasSeveralChars()); - if (ptNode.isTerminal()) { - writeTerminalId(ptNode.mTerminalId); - } - writeChildrenPosition(ptNode, formatOptions); - } - - private void writeTerminalData(final ArrayList<PtNodeArray> flatNodes, - final int terminalCount) throws IOException { - final byte[] freqBuf = new byte[terminalCount * FormatSpec.FREQUENCY_AND_FLAGS_SIZE]; - final byte[] terminalAddressTableBuf = - new byte[terminalCount * FormatSpec.TERMINAL_ADDRESS_TABLE_ADDRESS_SIZE]; - for (final PtNodeArray nodeArray : flatNodes) { - for (final PtNode ptNode : nodeArray.mData) { - if (ptNode.isTerminal()) { - BinaryDictEncoderUtils.writeUIntToBuffer(freqBuf, - ptNode.mTerminalId * FormatSpec.FREQUENCY_AND_FLAGS_SIZE, - ptNode.mFrequency, FormatSpec.FREQUENCY_AND_FLAGS_SIZE); - BinaryDictEncoderUtils.writeUIntToBuffer(terminalAddressTableBuf, - ptNode.mTerminalId * FormatSpec.TERMINAL_ADDRESS_TABLE_ADDRESS_SIZE, - ptNode.mCachedAddressAfterUpdate, - FormatSpec.TERMINAL_ADDRESS_TABLE_ADDRESS_SIZE); - } - } - } - mFreqOutStream.write(freqBuf); - mTerminalAddressTableOutStream.write(terminalAddressTableBuf); - } - - private void initUnigramTimestamps(final int terminalCount) throws IOException { - // Initial value of time stamps for each word is 0. - final byte[] unigramTimestampBuf = - new byte[terminalCount * FormatSpec.UNIGRAM_TIMESTAMP_SIZE]; - mUnigramTimestampOutStream.write(unigramTimestampBuf); + public void writePtNode( + PtNode ptNode, int parentPosition, FormatOptions formatOptions, FusionDictionary dict) { } } diff --git a/java/src/com/android/inputmethod/latin/makedict/Ver4DictUpdater.java b/java/src/com/android/inputmethod/latin/makedict/Ver4DictUpdater.java index 91d9cf345..6298295c6 100644 --- a/java/src/com/android/inputmethod/latin/makedict/Ver4DictUpdater.java +++ b/java/src/com/android/inputmethod/latin/makedict/Ver4DictUpdater.java @@ -40,6 +40,7 @@ import java.util.Iterator; @UsedForTesting public class Ver4DictUpdater extends Ver4DictDecoder implements DictUpdater { private static final String TAG = Ver4DictUpdater.class.getSimpleName(); + private static final int MAX_JUMPS = 10000; private OutputStream mDictStream; private final File mFrequencyFile; @@ -54,8 +55,6 @@ public class Ver4DictUpdater extends Ver4DictDecoder implements DictUpdater { } private static class BigramContentUpdater extends SparseTableContentUpdater { - private final boolean mHasTimestamp; - public BigramContentUpdater(final String name, final File baseDir, final boolean hasTimestamp) { super(name + FormatSpec.BIGRAM_FILE_EXTENSION, @@ -63,7 +62,6 @@ public class Ver4DictUpdater extends Ver4DictDecoder implements DictUpdater { BigramContentReader.getContentFilenames(name, hasTimestamp), BigramContentReader.getContentIds(hasTimestamp), new DictionaryBufferFromWritableByteBufferFactory()); - mHasTimestamp = hasTimestamp; } public void insertBigramEntries(final int terminalId, final int frequency, @@ -149,7 +147,7 @@ public class Ver4DictUpdater extends Ver4DictDecoder implements DictUpdater { mDictBuffer.position(wordPos); final int flags = PtNodeReader.readPtNodeOptionFlags(mDictBuffer); mDictBuffer.position(wordPos); - mDictBuffer.put((byte) DynamicBinaryDictIOUtils.markAsDeleted(flags)); + mDictBuffer.put((byte)markAsDeleted(flags)); } } @@ -186,7 +184,7 @@ public class Ver4DictUpdater extends Ver4DictDecoder implements DictUpdater { skipPtNode(formatOptions); } if (!readAndFollowForwardLink()) break; - } while (jumpCount++ < DynamicBinaryDictIOUtils.MAX_JUMPS); + } while (jumpCount++ < MAX_JUMPS); setPosition(originalPos); } @@ -219,7 +217,7 @@ public class Ver4DictUpdater extends Ver4DictDecoder implements DictUpdater { final int originalPos = getPosition(); setPosition(nodeArrayPos); int jumpCount = 0; - while (jumpCount++ < DynamicBinaryDictIOUtils.MAX_JUMPS) { + while (jumpCount++ < MAX_JUMPS) { final int ptNodeCount = readPtNodeCount(); for (int i = 0; i < ptNodeCount; ++i) { skipPtNode(formatOptions); @@ -738,8 +736,7 @@ public class Ver4DictUpdater extends Ver4DictDecoder implements DictUpdater { mDictBuffer.put((byte) newFlags); updateFrequency(terminalId, frequency); - insertBigrams(terminalId, frequency, - DynamicBinaryDictIOUtils.resolveBigramPositions(this, bigramStrings)); + insertBigrams(terminalId, frequency, resolveBigramPositions(this, bigramStrings)); insertShortcuts(terminalId, shortcuts); } @@ -768,8 +765,30 @@ public class Ver4DictUpdater extends Ver4DictDecoder implements DictUpdater { insertTerminalPosition(posOfTerminal); close(); - insertBigrams(newTerminalId, frequency, - DynamicBinaryDictIOUtils.resolveBigramPositions(this, bigramStrings)); + insertBigrams(newTerminalId, frequency, resolveBigramPositions(this, bigramStrings)); insertShortcuts(newTerminalId, shortcuts); } + + /** + * Converts a list of WeightedString to a list of PendingAttribute. + */ + private static ArrayList<PendingAttribute> resolveBigramPositions(final DictUpdater dictUpdater, + final ArrayList<WeightedString> bigramStrings) + throws IOException, UnsupportedFormatException { + if (bigramStrings == null) return CollectionUtils.newArrayList(); + final ArrayList<PendingAttribute> bigrams = CollectionUtils.newArrayList(); + for (final WeightedString bigram : bigramStrings) { + final int pos = dictUpdater.getTerminalPosition(bigram.mWord); + if (pos == FormatSpec.NOT_VALID_WORD) { + // TODO: figure out what is the correct thing to do here. + } else { + bigrams.add(new PendingAttribute(bigram.mFrequency, pos)); + } + } + return bigrams; + } + + private static int markAsDeleted(final int flags) { + return (flags & (~FormatSpec.MASK_CHILDREN_ADDRESS_TYPE)) | FormatSpec.FLAG_IS_DELETED; + } } diff --git a/java/src/com/android/inputmethod/latin/personalization/DecayingExpandableBinaryDictionaryBase.java b/java/src/com/android/inputmethod/latin/personalization/DecayingExpandableBinaryDictionaryBase.java index 296733fad..9b573b4b8 100644 --- a/java/src/com/android/inputmethod/latin/personalization/DecayingExpandableBinaryDictionaryBase.java +++ b/java/src/com/android/inputmethod/latin/personalization/DecayingExpandableBinaryDictionaryBase.java @@ -95,8 +95,6 @@ public abstract class DecayingExpandableBinaryDictionaryBase extends ExpandableB @Override protected Map<String, String> getHeaderAttributeMap() { HashMap<String, String> attributeMap = new HashMap<String, String>(); - attributeMap.put(FormatSpec.FileHeader.SUPPORTS_DYNAMIC_UPDATE_ATTRIBUTE, - FormatSpec.FileHeader.ATTRIBUTE_VALUE_TRUE); attributeMap.put(FormatSpec.FileHeader.USES_FORGETTING_CURVE_ATTRIBUTE, FormatSpec.FileHeader.ATTRIBUTE_VALUE_TRUE); attributeMap.put(FormatSpec.FileHeader.HAS_HISTORICAL_INFO_ATTRIBUTE, diff --git a/java/src/com/android/inputmethod/latin/utils/SpannableStringUtils.java b/java/src/com/android/inputmethod/latin/utils/SpannableStringUtils.java index b51fd9377..be0955456 100644 --- a/java/src/com/android/inputmethod/latin/utils/SpannableStringUtils.java +++ b/java/src/com/android/inputmethod/latin/utils/SpannableStringUtils.java @@ -40,12 +40,17 @@ public final class SpannableStringUtils { * are out of range in <code>dest</code>. */ public static void copyNonParagraphSuggestionSpansFrom(Spanned source, int start, int end, - Spannable dest, int destoff) { + Spannable dest, int destoff) { Object[] spans = source.getSpans(start, end, SuggestionSpan.class); for (int i = 0; i < spans.length; i++) { int fl = source.getSpanFlags(spans[i]); - if (0 != (fl & Spannable.SPAN_PARAGRAPH)) continue; + // We don't care about the PARAGRAPH flag in LatinIME code. However, if this flag + // is set, Spannable#setSpan will throw an exception unless the span is on the edge + // of a word. But the spans have been split into two by the getText{Before,After}Cursor + // methods, so after concatenation they may end in the middle of a word. + // Since we don't use them, we can just remove them and avoid crashing. + fl &= ~Spannable.SPAN_PARAGRAPH; int st = source.getSpanStart(spans[i]); int en = source.getSpanEnd(spans[i]); diff --git a/java/src/com/android/inputmethod/latin/utils/UserHistoryDictIOUtils.java b/java/src/com/android/inputmethod/latin/utils/UserHistoryDictIOUtils.java index a2c3ed44d..db628fe18 100644 --- a/java/src/com/android/inputmethod/latin/utils/UserHistoryDictIOUtils.java +++ b/java/src/com/android/inputmethod/latin/utils/UserHistoryDictIOUtils.java @@ -95,8 +95,7 @@ public final class UserHistoryDictIOUtils { static FusionDictionary constructFusionDictionary(final BigramDictionaryInterface dict, final UserHistoryDictionaryBigramList bigrams, final HashMap<String, String> options) { final FusionDictionary fusionDict = new FusionDictionary(new PtNodeArray(), - new FusionDictionary.DictionaryOptions(options, false, - false)); + new FusionDictionary.DictionaryOptions(options)); int profTotal = 0; for (final String word1 : bigrams.keySet()) { final HashMap<String, Byte> word1Bigrams = bigrams.getBigrams(word1); diff --git a/java/src/com/android/inputmethod/latin/utils/UserHistoryForgettingCurveUtils.java b/java/src/com/android/inputmethod/latin/utils/UserHistoryForgettingCurveUtils.java deleted file mode 100644 index 677035ed6..000000000 --- a/java/src/com/android/inputmethod/latin/utils/UserHistoryForgettingCurveUtils.java +++ /dev/null @@ -1,242 +0,0 @@ -/* - * Copyright (C) 2012 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.utils; - -import android.util.Log; - -import java.util.concurrent.TimeUnit; - -import com.android.inputmethod.annotations.UsedForTesting; - -@UsedForTesting -public final class UserHistoryForgettingCurveUtils { - private static final String TAG = UserHistoryForgettingCurveUtils.class.getSimpleName(); - private static final boolean DEBUG = false; - private static final int DEFAULT_FC_FREQ = 127; - private static final int BOOSTED_FC_FREQ = 200; - private static int FC_FREQ_MAX = DEFAULT_FC_FREQ; - /* package */ static final int COUNT_MAX = 3; - private static final int FC_LEVEL_MAX = 3; - /* package */ static final int ELAPSED_TIME_MAX = 15; - private static final int ELAPSED_TIME_INTERVAL_HOURS = 6; - private static final long ELAPSED_TIME_INTERVAL_MILLIS = - TimeUnit.HOURS.toMillis(ELAPSED_TIME_INTERVAL_HOURS); - private static final int HALF_LIFE_HOURS = 48; - private static final int MAX_PUSH_ELAPSED = (FC_LEVEL_MAX + 1) * (ELAPSED_TIME_MAX + 1); - - public static void boostMaxFreqForDebug() { - FC_FREQ_MAX = BOOSTED_FC_FREQ; - } - - public static void resetMaxFreqForDebug() { - FC_FREQ_MAX = DEFAULT_FC_FREQ; - } - - private UserHistoryForgettingCurveUtils() { - // This utility class is not publicly instantiable. - } - - public static final class ForgettingCurveParams { - private byte mFc; - long mLastTouchedTime = 0; - private final boolean mIsValid; - - private void updateLastTouchedTime() { - mLastTouchedTime = System.currentTimeMillis(); - } - - public ForgettingCurveParams(boolean isValid) { - this(System.currentTimeMillis(), isValid); - } - - private ForgettingCurveParams(long now, boolean isValid) { - this(pushCount((byte)0, isValid), now, now, isValid); - } - - /** This constructor is called when the user history bigram dictionary is being restored. */ - public ForgettingCurveParams(int fc, long now, long last) { - // All words with level >= 1 had been saved. - // Invalid words with level == 0 had been saved. - // Valid words words with level == 0 had *not* been saved. - this(fc, now, last, fcToLevel((byte)fc) > 0); - } - - private ForgettingCurveParams(int fc, long now, long last, boolean isValid) { - mIsValid = isValid; - mFc = (byte)fc; - mLastTouchedTime = last; - updateElapsedTime(now); - } - - public boolean isValid() { - return mIsValid; - } - - public byte getFc() { - updateElapsedTime(System.currentTimeMillis()); - return mFc; - } - - public int getFrequency() { - updateElapsedTime(System.currentTimeMillis()); - return UserHistoryForgettingCurveUtils.fcToFreq(mFc); - } - - public int notifyTypedAgainAndGetFrequency() { - updateLastTouchedTime(); - // TODO: Check whether this word is valid or not - mFc = pushCount(mFc, false); - return UserHistoryForgettingCurveUtils.fcToFreq(mFc); - } - - private void updateElapsedTime(long now) { - final int elapsedTimeCount = - (int)((now - mLastTouchedTime) / ELAPSED_TIME_INTERVAL_MILLIS); - if (elapsedTimeCount <= 0) { - return; - } - if (elapsedTimeCount >= MAX_PUSH_ELAPSED) { - mLastTouchedTime = now; - mFc = 0; - return; - } - for (int i = 0; i < elapsedTimeCount; ++i) { - mLastTouchedTime += ELAPSED_TIME_INTERVAL_MILLIS; - mFc = pushElapsedTime(mFc); - } - } - } - - @UsedForTesting - /* package */ static int fcToElapsedTime(byte fc) { - return fc & 0x0F; - } - - @UsedForTesting - /* package */ static int fcToCount(byte fc) { - return (fc >> 4) & 0x03; - } - - @UsedForTesting - /* package */ static int fcToLevel(byte fc) { - return (fc >> 6) & 0x03; - } - - @UsedForTesting - private static int calcFreq(int elapsedTime, int count, int level) { - if (level <= 0) { - // Reserved words, just return -1 - return -1; - } - if (count == COUNT_MAX) { - // Temporary promote because it's frequently typed recently - ++level; - } - final int et = Math.min(FC_FREQ_MAX, Math.max(0, elapsedTime)); - final int l = Math.min(FC_LEVEL_MAX, Math.max(0, level)); - return MathUtils.SCORE_TABLE[l - 1][et]; - } - - /* pakcage */ static byte calcFc(int elapsedTime, int count, int level) { - final int et = Math.min(FC_FREQ_MAX, Math.max(0, elapsedTime)); - final int c = Math.min(COUNT_MAX, Math.max(0, count)); - final int l = Math.min(FC_LEVEL_MAX, Math.max(0, level)); - return (byte)(et | (c << 4) | (l << 6)); - } - - public static int fcToFreq(byte fc) { - final int elapsedTime = fcToElapsedTime(fc); - final int count = fcToCount(fc); - final int level = fcToLevel(fc); - return calcFreq(elapsedTime, count, level); - } - - @UsedForTesting - public static byte pushElapsedTime(byte fc) { - int elapsedTime = fcToElapsedTime(fc); - int count = fcToCount(fc); - int level = fcToLevel(fc); - if (elapsedTime >= ELAPSED_TIME_MAX) { - // Downgrade level - elapsedTime = 0; - count = COUNT_MAX; - --level; - } else { - ++elapsedTime; - } - return calcFc(elapsedTime, count, level); - } - - @UsedForTesting - public static byte pushCount(byte fc, boolean isValid) { - final int elapsedTime = fcToElapsedTime(fc); - int count = fcToCount(fc); - int level = fcToLevel(fc); - if ((elapsedTime == 0 && count >= COUNT_MAX) || (isValid && level == 0)) { - // Upgrade level - ++level; - count = 0; - if (DEBUG) { - Log.d(TAG, "Upgrade level."); - } - } else { - ++count; - } - return calcFc(0, count, level); - } - - // TODO: isValid should be false for a word whose frequency is 0, - // or that is not in the dictionary. - /** - * Check wheather we should save the bigram to the SQL DB or not - */ - public static boolean needsToSave(byte fc, boolean isValid, boolean addLevel0Bigram) { - int level = fcToLevel(fc); - if (level == 0) { - if (isValid || !addLevel0Bigram) { - return false; - } - } - final int elapsedTime = fcToElapsedTime(fc); - return (elapsedTime < ELAPSED_TIME_MAX - 1 || level > 0); - } - - private static final class MathUtils { - public static final int[][] SCORE_TABLE = new int[FC_LEVEL_MAX][ELAPSED_TIME_MAX + 1]; - static { - for (int i = 0; i < FC_LEVEL_MAX; ++i) { - final float initialFreq; - if (i >= 2) { - initialFreq = FC_FREQ_MAX; - } else if (i == 1) { - initialFreq = FC_FREQ_MAX / 2; - } else if (i == 0) { - initialFreq = FC_FREQ_MAX / 4; - } else { - continue; - } - for (int j = 0; j < ELAPSED_TIME_MAX; ++j) { - final float elapsedHours = j * ELAPSED_TIME_INTERVAL_HOURS; - final float freq = initialFreq - * (float)Math.pow(initialFreq, elapsedHours / HALF_LIFE_HOURS); - final int intFreq = Math.min(FC_FREQ_MAX, Math.max(0, (int)freq)); - SCORE_TABLE[i][j] = intFreq; - } - } - } - } -} diff --git a/native/jni/Android.mk b/native/jni/Android.mk index e11e706f3..7827db302 100644 --- a/native/jni/Android.mk +++ b/native/jni/Android.mk @@ -39,87 +39,7 @@ endif # TARGET_ARCH # To suppress compiler warnings for unused variables/functions used for debug features etc. LOCAL_CFLAGS += -Wno-unused-parameter -Wno-unused-function -LATIN_IME_JNI_SRC_FILES := \ - com_android_inputmethod_keyboard_ProximityInfo.cpp \ - com_android_inputmethod_latin_BinaryDictionary.cpp \ - com_android_inputmethod_latin_DicTraverseSession.cpp \ - com_android_inputmethod_latin_makedict_Ver3DictDecoder.cpp \ - jni_common.cpp - -LATIN_IME_CORE_SRC_FILES := \ - suggest/core/suggest.cpp \ - $(addprefix suggest/core/dicnode/, \ - dic_node.cpp \ - dic_node_utils.cpp \ - dic_nodes_cache.cpp) \ - $(addprefix suggest/core/dictionary/, \ - bigram_dictionary.cpp \ - bloom_filter.cpp \ - dictionary.cpp \ - digraph_utils.cpp \ - error_type_utils.cpp \ - multi_bigram_map.cpp \ - unigram_property.cpp) \ - $(addprefix suggest/core/layout/, \ - additional_proximity_chars.cpp \ - proximity_info.cpp \ - proximity_info_params.cpp \ - proximity_info_state.cpp \ - proximity_info_state_utils.cpp) \ - suggest/core/policy/weighting.cpp \ - suggest/core/session/dic_traverse_session.cpp \ - $(addprefix suggest/policyimpl/dictionary/, \ - header/header_policy.cpp \ - header/header_read_write_utils.cpp \ - shortcut/shortcut_list_reading_utils.cpp \ - structure/dictionary_structure_with_buffer_policy_factory.cpp) \ - $(addprefix suggest/policyimpl/dictionary/bigram/, \ - bigram_list_read_write_utils.cpp \ - ver4_bigram_list_policy.cpp) \ - $(addprefix suggest/policyimpl/dictionary/structure/pt_common/, \ - dynamic_pt_gc_event_listeners.cpp \ - dynamic_pt_reading_helper.cpp \ - dynamic_pt_reading_utils.cpp \ - dynamic_pt_updating_helper.cpp \ - dynamic_pt_writing_utils.cpp) \ - $(addprefix suggest/policyimpl/dictionary/structure/v2/, \ - patricia_trie_policy.cpp \ - patricia_trie_reading_utils.cpp) \ - $(addprefix suggest/policyimpl/dictionary/structure/v4/, \ - ver4_dict_buffers.cpp \ - ver4_dict_constants.cpp \ - ver4_patricia_trie_node_reader.cpp \ - ver4_patricia_trie_node_writer.cpp \ - ver4_patricia_trie_policy.cpp \ - ver4_patricia_trie_reading_utils.cpp \ - ver4_patricia_trie_writing_helper.cpp) \ - $(addprefix suggest/policyimpl/dictionary/structure/v4/content/, \ - bigram_dict_content.cpp \ - probability_dict_content.cpp \ - shortcut_dict_content.cpp \ - sparse_table_dict_content.cpp \ - terminal_position_lookup_table.cpp) \ - $(addprefix suggest/policyimpl/dictionary/utils/, \ - buffer_with_extendable_buffer.cpp \ - byte_array_utils.cpp \ - dict_file_writing_utils.cpp \ - file_utils.cpp \ - forgetting_curve_utils.cpp \ - format_utils.cpp \ - mmapped_buffer.cpp \ - sparse_table.cpp) \ - suggest/policyimpl/gesture/gesture_suggest_policy_factory.cpp \ - $(addprefix suggest/policyimpl/typing/, \ - scoring_params.cpp \ - typing_scoring.cpp \ - typing_suggest_policy.cpp \ - typing_traversal.cpp \ - typing_weighting.cpp) \ - $(addprefix utils/, \ - autocorrection_threshold_utils.cpp \ - char_utils.cpp \ - log_utils.cpp \ - time_keeper.cpp) +include $(LOCAL_PATH)/NativeFileList.mk LOCAL_SRC_FILES := \ $(LATIN_IME_JNI_SRC_FILES) \ @@ -172,6 +92,4 @@ LOCAL_LDFLAGS += -ldl include $(BUILD_SHARED_LIBRARY) #################### Clean up the tmp vars -LATIN_IME_CORE_SRC_FILES := -LATIN_IME_JNI_SRC_FILES := -LATIN_IME_SRC_DIR := +include $(LOCAL_PATH)/CleanupNativeFileList.mk diff --git a/native/jni/CleanupNativeFileList.mk b/native/jni/CleanupNativeFileList.mk new file mode 100644 index 000000000..5420f16f9 --- /dev/null +++ b/native/jni/CleanupNativeFileList.mk @@ -0,0 +1,17 @@ +# Copyright (C) 2013 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. + +LATIN_IME_CORE_SRC_FILES := +LATIN_IME_JNI_SRC_FILES := +LATIN_IME_SRC_DIR := diff --git a/native/jni/NativeFileList.mk b/native/jni/NativeFileList.mk new file mode 100644 index 000000000..d80a1115f --- /dev/null +++ b/native/jni/NativeFileList.mk @@ -0,0 +1,94 @@ +# Copyright (C) 2013 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. + +LATIN_IME_JNI_SRC_FILES := \ + com_android_inputmethod_keyboard_ProximityInfo.cpp \ + com_android_inputmethod_latin_BinaryDictionary.cpp \ + com_android_inputmethod_latin_DicTraverseSession.cpp \ + jni_common.cpp + +LATIN_IME_CORE_SRC_FILES := \ + suggest/core/suggest.cpp \ + $(addprefix suggest/core/dicnode/, \ + dic_node.cpp \ + dic_node_utils.cpp \ + dic_nodes_cache.cpp) \ + $(addprefix suggest/core/dictionary/, \ + bigram_dictionary.cpp \ + bloom_filter.cpp \ + dictionary.cpp \ + digraph_utils.cpp \ + error_type_utils.cpp \ + multi_bigram_map.cpp \ + unigram_property.cpp) \ + $(addprefix suggest/core/layout/, \ + additional_proximity_chars.cpp \ + proximity_info.cpp \ + proximity_info_params.cpp \ + proximity_info_state.cpp \ + proximity_info_state_utils.cpp) \ + suggest/core/policy/weighting.cpp \ + suggest/core/session/dic_traverse_session.cpp \ + $(addprefix suggest/policyimpl/dictionary/, \ + header/header_policy.cpp \ + header/header_read_write_utils.cpp \ + shortcut/shortcut_list_reading_utils.cpp \ + structure/dictionary_structure_with_buffer_policy_factory.cpp) \ + $(addprefix suggest/policyimpl/dictionary/bigram/, \ + bigram_list_read_write_utils.cpp \ + ver4_bigram_list_policy.cpp) \ + $(addprefix suggest/policyimpl/dictionary/structure/pt_common/, \ + dynamic_pt_gc_event_listeners.cpp \ + dynamic_pt_reading_helper.cpp \ + dynamic_pt_reading_utils.cpp \ + dynamic_pt_updating_helper.cpp \ + dynamic_pt_writing_utils.cpp) \ + $(addprefix suggest/policyimpl/dictionary/structure/v2/, \ + patricia_trie_policy.cpp \ + patricia_trie_reading_utils.cpp) \ + $(addprefix suggest/policyimpl/dictionary/structure/v4/, \ + ver4_dict_buffers.cpp \ + ver4_dict_constants.cpp \ + ver4_patricia_trie_node_reader.cpp \ + ver4_patricia_trie_node_writer.cpp \ + ver4_patricia_trie_policy.cpp \ + ver4_patricia_trie_reading_utils.cpp \ + ver4_patricia_trie_writing_helper.cpp) \ + $(addprefix suggest/policyimpl/dictionary/structure/v4/content/, \ + bigram_dict_content.cpp \ + probability_dict_content.cpp \ + shortcut_dict_content.cpp \ + sparse_table_dict_content.cpp \ + terminal_position_lookup_table.cpp) \ + $(addprefix suggest/policyimpl/dictionary/utils/, \ + buffer_with_extendable_buffer.cpp \ + byte_array_utils.cpp \ + dict_file_writing_utils.cpp \ + file_utils.cpp \ + forgetting_curve_utils.cpp \ + format_utils.cpp \ + mmapped_buffer.cpp \ + sparse_table.cpp) \ + suggest/policyimpl/gesture/gesture_suggest_policy_factory.cpp \ + $(addprefix suggest/policyimpl/typing/, \ + scoring_params.cpp \ + typing_scoring.cpp \ + typing_suggest_policy.cpp \ + typing_traversal.cpp \ + typing_weighting.cpp) \ + $(addprefix utils/, \ + autocorrection_threshold_utils.cpp \ + char_utils.cpp \ + log_utils.cpp \ + time_keeper.cpp) diff --git a/native/jni/com_android_inputmethod_latin_makedict_Ver3DictDecoder.cpp b/native/jni/com_android_inputmethod_latin_makedict_Ver3DictDecoder.cpp deleted file mode 100644 index 15088b65a..000000000 --- a/native/jni/com_android_inputmethod_latin_makedict_Ver3DictDecoder.cpp +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (C) 2013 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. - */ - -#define LOG_TAG "LatinIME: jni: Ver3DictDecoder" - -#include "com_android_inputmethod_latin_makedict_Ver3DictDecoder.h" - -#include "defines.h" -#include "jni.h" -#include "jni_common.h" - -namespace latinime { -static int latinime_Ver3DictDecoder_doNothing(JNIEnv *env, jclass clazz) { - // This is a phony method for test - it does nothing. It just returns some value - // unlikely to be in memory by chance for testing purposes. - // TODO: remove this method. - return 2097; -} - -static const JNINativeMethod sMethods[] = { - { - // TODO: remove this entry when we have one useful method in here - const_cast<char *>("doNothing"), - const_cast<char *>("()I"), - reinterpret_cast<void *>(latinime_Ver3DictDecoder_doNothing) - }, -}; - -int register_Ver3DictDecoder(JNIEnv *env) { - const char *const kClassPathName = - "com/android/inputmethod/latin/makedict/Ver3DictDecoder"; - return registerNativeMethods(env, kClassPathName, sMethods, NELEMS(sMethods)); -} -} // namespace latinime diff --git a/native/jni/jni_common.cpp b/native/jni/jni_common.cpp index 3a8f4362d..f2867d7c3 100644 --- a/native/jni/jni_common.cpp +++ b/native/jni/jni_common.cpp @@ -18,12 +18,9 @@ #include "jni_common.h" -#ifndef HOST_TOOL #include "com_android_inputmethod_keyboard_ProximityInfo.h" #include "com_android_inputmethod_latin_BinaryDictionary.h" #include "com_android_inputmethod_latin_DicTraverseSession.h" -#endif -#include "com_android_inputmethod_latin_makedict_Ver3DictDecoder.h" #include "defines.h" /* @@ -41,7 +38,6 @@ jint JNI_OnLoad(JavaVM *vm, void *reserved) { AKLOGE("ERROR: JNIEnv is invalid"); return -1; } -#ifndef HOST_TOOL if (!latinime::register_BinaryDictionary(env)) { AKLOGE("ERROR: BinaryDictionary native registration failed"); return -1; @@ -54,11 +50,6 @@ jint JNI_OnLoad(JavaVM *vm, void *reserved) { AKLOGE("ERROR: ProximityInfo native registration failed"); return -1; } -#endif - if (!latinime::register_Ver3DictDecoder(env)) { - AKLOGE("ERROR: Ver3DictDecoder native registration failed"); - return -1; - } /* success -- return valid version number */ return JNI_VERSION_1_6; } diff --git a/native/jni/src/defines.h b/native/jni/src/defines.h index 9a26fe051..1969ebae0 100644 --- a/native/jni/src/defines.h +++ b/native/jni/src/defines.h @@ -87,12 +87,21 @@ AK_FORCE_INLINE static int intArrayToCharArray(const int *const source, const in } #if defined(FLAG_DO_PROFILE) || defined(FLAG_DBG) +#if defined(__ANDROID__) #include <android/log.h> +#endif // defined(__ANDROID__) #ifndef LOG_TAG #define LOG_TAG "LatinIME: " #endif // LOG_TAG + +#if defined(HOST_TOOL) +#include <stdio.h> +#define AKLOGE(fmt, ...) printf(fmt "\n", ##__VA_ARGS__) +#define AKLOGI(fmt, ...) printf(fmt "\n", ##__VA_ARGS__) +#else // defined(HOST_TOOL) #define AKLOGE(fmt, ...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, fmt, ##__VA_ARGS__) #define AKLOGI(fmt, ...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, fmt, ##__VA_ARGS__) +#endif // defined(HOST_TOOL) #define DUMP_RESULT(words, frequencies) do { dumpResult(words, frequencies); } while (0) #define DUMP_WORD(word, length) do { dumpWord(word, length); } while (0) diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.cpp index 34fecc25f..9afb5f221 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.cpp +++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.cpp @@ -33,8 +33,7 @@ const char *const Ver4DictConstants::SHORTCUT_CONTENT_TABLE_FILE_EXTENSION = ".shortcut_index_shortcut"; // Version 4 dictionary size is implicitly limited to 8MB due to 3-byte offsets. -// TODO: Make MAX_DICTIONARY_SIZE 8MB. -const int Ver4DictConstants::MAX_DICTIONARY_SIZE = 2 * 1024 * 1024; +const int Ver4DictConstants::MAX_DICTIONARY_SIZE = 8 * 1024 * 1024; // Extended region size, which is not GCed region size in dict file + additional buffer size, is // limited to 1MB to prevent from inefficient traversing. const int Ver4DictConstants::MAX_DICT_EXTENDED_REGION_SIZE = 1 * 1024 * 1024; diff --git a/native/jni/src/suggest/policyimpl/dictionary/utils/file_utils.cpp b/native/jni/src/suggest/policyimpl/dictionary/utils/file_utils.cpp index 1f25cfa1e..9441a75fc 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/utils/file_utils.cpp +++ b/native/jni/src/suggest/policyimpl/dictionary/utils/file_utils.cpp @@ -53,6 +53,11 @@ namespace latinime { // Remove a directory and all files in the directory. /* static */ bool FileUtils::removeDirAndFiles(const char *const dirPath) { + return removeDirAndFiles(dirPath, 5 /* maxTries */); +} + +// Remove a directory and all files in the directory, trying up to maxTimes. +/* static */ bool FileUtils::removeDirAndFiles(const char *const dirPath, const int maxTries) { DIR *const dir = opendir(dirPath); if (dir == NULL) { AKLOGE("Cannot open dir %s.", dirPath); @@ -60,7 +65,7 @@ namespace latinime { } struct dirent *dirent; while ((dirent = readdir(dir)) != NULL) { - if (dirent->d_type != DT_REG) { + if (dirent->d_type == DT_DIR) { continue; } const int filePathBufSize = getFilePathBufSize(dirPath, dirent->d_name); @@ -74,8 +79,14 @@ namespace latinime { } closedir(dir); if (remove(dirPath) != 0) { - AKLOGE("Cannot remove directory %s.", dirPath); - return false; + if (maxTries > 0) { + // On NFS, deleting files sometimes creates new files. I'm not sure what the + // correct way of dealing with this is, but for the time being, this seems to work. + removeDirAndFiles(dirPath, maxTries - 1); + } else { + AKLOGE("Cannot remove directory %s.", dirPath); + return false; + } } return true; } diff --git a/native/jni/src/suggest/policyimpl/dictionary/utils/file_utils.h b/native/jni/src/suggest/policyimpl/dictionary/utils/file_utils.h index 3e84a3038..4f1b93a6a 100644 --- a/native/jni/src/suggest/policyimpl/dictionary/utils/file_utils.h +++ b/native/jni/src/suggest/policyimpl/dictionary/utils/file_utils.h @@ -53,6 +53,8 @@ class FileUtils { private: DISALLOW_IMPLICIT_CONSTRUCTORS(FileUtils); + + static bool removeDirAndFiles(const char *const dirPath, const int maxTries); }; } // namespace latinime #endif /* LATINIME_FILE_UTILS_H */ diff --git a/tests/src/com/android/inputmethod/latin/BinaryDictionaryDecayingTests.java b/tests/src/com/android/inputmethod/latin/BinaryDictionaryDecayingTests.java index e0276513a..098b211d9 100644 --- a/tests/src/com/android/inputmethod/latin/BinaryDictionaryDecayingTests.java +++ b/tests/src/com/android/inputmethod/latin/BinaryDictionaryDecayingTests.java @@ -115,19 +115,16 @@ public class BinaryDictionaryDecayingTests extends AndroidTestCase { getContext().getCacheDir()); FileUtils.deleteRecursively(file); Map<String, String> attributeMap = new HashMap<String, String>(); - attributeMap.put(FormatSpec.FileHeader.SUPPORTS_DYNAMIC_UPDATE_ATTRIBUTE, - FormatSpec.FileHeader.ATTRIBUTE_VALUE_TRUE); attributeMap.put(FormatSpec.FileHeader.USES_FORGETTING_CURVE_ATTRIBUTE, FormatSpec.FileHeader.ATTRIBUTE_VALUE_TRUE); attributeMap.put(FormatSpec.FileHeader.HAS_HISTORICAL_INFO_ATTRIBUTE, FormatSpec.FileHeader.ATTRIBUTE_VALUE_TRUE); - final String headerFileName = file.getName() + FormatSpec.HEADER_FILE_EXTENSION; if (BinaryDictionary.createEmptyDictFile(file.getAbsolutePath(), FormatSpec.VERSION4, attributeMap)) { return file; } else { - throw new IOException("Empty dictionary " + file.getAbsolutePath() + " " - + headerFileName + " cannot be created."); + throw new IOException("Empty dictionary " + file.getAbsolutePath() + + " cannot be created."); } } diff --git a/tests/src/com/android/inputmethod/latin/BinaryDictionaryTests.java b/tests/src/com/android/inputmethod/latin/BinaryDictionaryTests.java index cfc4c762a..a26c25886 100644 --- a/tests/src/com/android/inputmethod/latin/BinaryDictionaryTests.java +++ b/tests/src/com/android/inputmethod/latin/BinaryDictionaryTests.java @@ -69,8 +69,6 @@ public class BinaryDictionaryTests extends AndroidTestCase { file.delete(); file.mkdir(); Map<String, String> attributeMap = new HashMap<String, String>(); - attributeMap.put(FormatSpec.FileHeader.SUPPORTS_DYNAMIC_UPDATE_ATTRIBUTE, - FormatSpec.FileHeader.ATTRIBUTE_VALUE_TRUE); if (BinaryDictionary.createEmptyDictFile(file.getAbsolutePath(), FormatSpec.VERSION4, attributeMap)) { return file; diff --git a/tests/src/com/android/inputmethod/latin/FusionDictionaryTests.java b/tests/src/com/android/inputmethod/latin/FusionDictionaryTests.java index cadd0f8f3..e211d94b8 100644 --- a/tests/src/com/android/inputmethod/latin/FusionDictionaryTests.java +++ b/tests/src/com/android/inputmethod/latin/FusionDictionaryTests.java @@ -31,7 +31,7 @@ import java.util.HashMap; public class FusionDictionaryTests extends AndroidTestCase { public void testFindWordInTree() { FusionDictionary dict = new FusionDictionary(new PtNodeArray(), - new FusionDictionary.DictionaryOptions(new HashMap<String,String>(), false, false)); + new FusionDictionary.DictionaryOptions(new HashMap<String,String>())); dict.add("abc", 10, null, false /* isNotAWord */); assertNull(FusionDictionary.findWordInTree(dict.mRootNodeArray, "aaa")); diff --git a/tests/src/com/android/inputmethod/latin/makedict/BinaryDictDecoderEncoderTests.java b/tests/src/com/android/inputmethod/latin/makedict/BinaryDictDecoderEncoderTests.java index e3ec2eca9..f52f5e73c 100644 --- a/tests/src/com/android/inputmethod/latin/makedict/BinaryDictDecoderEncoderTests.java +++ b/tests/src/com/android/inputmethod/latin/makedict/BinaryDictDecoderEncoderTests.java @@ -169,8 +169,7 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase { long now = -1, diff = -1; try { - final DictEncoder dictEncoder = BinaryDictUtils.getDictEncoder(file, formatOptions, - getContext().getCacheDir()); + final DictEncoder dictEncoder = BinaryDictUtils.getDictEncoder(file, formatOptions); now = System.currentTimeMillis(); // If you need to dump the dict to a textual file, uncomment the line below and the @@ -226,8 +225,7 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase { final FormatSpec.FormatOptions formatOptions) { String result = " : buffer type = " + ((bufferType == BinaryDictUtils.USE_BYTE_BUFFER) ? "byte buffer" : "byte array"); - result += " : version = " + formatOptions.mVersion; - return result + ", supportsDynamicUpdate = " + formatOptions.mSupportsDynamicUpdate; + return result + " : version = " + formatOptions.mVersion; } // Tests for readDictionaryBinary and writeDictionaryBinary @@ -315,17 +313,11 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase { final List<String> results = CollectionUtils.newArrayList(); runReadAndWriteTests(results, BinaryDictUtils.USE_BYTE_BUFFER, - BinaryDictUtils.VERSION2); + BinaryDictUtils.VERSION2_OPTIONS); runReadAndWriteTests(results, BinaryDictUtils.USE_BYTE_BUFFER, - BinaryDictUtils.VERSION3_WITHOUT_DYNAMIC_UPDATE); + BinaryDictUtils.VERSION4_OPTIONS_WITHOUT_TIMESTAMP); runReadAndWriteTests(results, BinaryDictUtils.USE_BYTE_BUFFER, - BinaryDictUtils.VERSION3_WITH_DYNAMIC_UPDATE); - runReadAndWriteTests(results, BinaryDictUtils.USE_BYTE_BUFFER, - BinaryDictUtils.VERSION4_WITHOUT_DYNAMIC_UPDATE); - runReadAndWriteTests(results, BinaryDictUtils.USE_BYTE_BUFFER, - BinaryDictUtils.VERSION4_WITH_DYNAMIC_UPDATE); - runReadAndWriteTests(results, BinaryDictUtils.USE_BYTE_BUFFER, - BinaryDictUtils.VERSION4_WITH_DYNAMIC_UPDATE_AND_TIMESTAMP); + BinaryDictUtils.VERSION4_OPTIONS_WITH_TIMESTAMP); for (final String result : results) { Log.d(TAG, result); @@ -336,17 +328,11 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase { final List<String> results = CollectionUtils.newArrayList(); runReadAndWriteTests(results, BinaryDictUtils.USE_BYTE_ARRAY, - BinaryDictUtils.VERSION2); - runReadAndWriteTests(results, BinaryDictUtils.USE_BYTE_ARRAY, - BinaryDictUtils.VERSION3_WITHOUT_DYNAMIC_UPDATE); - runReadAndWriteTests(results, BinaryDictUtils.USE_BYTE_ARRAY, - BinaryDictUtils.VERSION3_WITH_DYNAMIC_UPDATE); + BinaryDictUtils.VERSION2_OPTIONS); runReadAndWriteTests(results, BinaryDictUtils.USE_BYTE_ARRAY, - BinaryDictUtils.VERSION4_WITHOUT_DYNAMIC_UPDATE); + BinaryDictUtils.VERSION4_OPTIONS_WITHOUT_TIMESTAMP); runReadAndWriteTests(results, BinaryDictUtils.USE_BYTE_ARRAY, - BinaryDictUtils.VERSION4_WITH_DYNAMIC_UPDATE); - runReadAndWriteTests(results, BinaryDictUtils.USE_BYTE_ARRAY, - BinaryDictUtils.VERSION4_WITH_DYNAMIC_UPDATE_AND_TIMESTAMP); + BinaryDictUtils.VERSION4_OPTIONS_WITH_TIMESTAMP); for (final String result : results) { Log.d(TAG, result); @@ -403,8 +389,6 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase { private long timeAndCheckReadUnigramsAndBigramsBinary(final File file, final List<String> words, final SparseArray<List<Integer>> bigrams, final int bufferType) { - FileInputStream inStream = null; - final TreeMap<Integer, String> resultWords = CollectionUtils.newTreeMap(); final TreeMap<Integer, ArrayList<PendingAttribute>> resultBigrams = CollectionUtils.newTreeMap(); @@ -420,14 +404,6 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase { Log.e(TAG, "IOException", e); } catch (UnsupportedFormatException e) { Log.e(TAG, "UnsupportedFormatException", e); - } finally { - if (inStream != null) { - try { - inStream.close(); - } catch (IOException e) { - // do nothing - } - } } checkWordMap(words, bigrams, resultWords, resultFreqs, resultBigrams); @@ -472,17 +448,11 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase { final ArrayList<String> results = CollectionUtils.newArrayList(); runReadUnigramsAndBigramsTests(results, BinaryDictUtils.USE_BYTE_BUFFER, - BinaryDictUtils.VERSION2); - runReadUnigramsAndBigramsTests(results, BinaryDictUtils.USE_BYTE_BUFFER, - BinaryDictUtils.VERSION3_WITHOUT_DYNAMIC_UPDATE); + BinaryDictUtils.VERSION2_OPTIONS); runReadUnigramsAndBigramsTests(results, BinaryDictUtils.USE_BYTE_BUFFER, - BinaryDictUtils.VERSION3_WITH_DYNAMIC_UPDATE); + BinaryDictUtils.VERSION4_OPTIONS_WITHOUT_TIMESTAMP); runReadUnigramsAndBigramsTests(results, BinaryDictUtils.USE_BYTE_BUFFER, - BinaryDictUtils.VERSION4_WITHOUT_DYNAMIC_UPDATE); - runReadUnigramsAndBigramsTests(results, BinaryDictUtils.USE_BYTE_BUFFER, - BinaryDictUtils.VERSION4_WITH_DYNAMIC_UPDATE); - runReadUnigramsAndBigramsTests(results, BinaryDictUtils.USE_BYTE_BUFFER, - BinaryDictUtils.VERSION4_WITH_DYNAMIC_UPDATE_AND_TIMESTAMP); + BinaryDictUtils.VERSION4_OPTIONS_WITH_TIMESTAMP); for (final String result : results) { Log.d(TAG, result); @@ -493,17 +463,11 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase { final ArrayList<String> results = CollectionUtils.newArrayList(); runReadUnigramsAndBigramsTests(results, BinaryDictUtils.USE_BYTE_ARRAY, - BinaryDictUtils.VERSION2); - runReadUnigramsAndBigramsTests(results, BinaryDictUtils.USE_BYTE_ARRAY, - BinaryDictUtils.VERSION3_WITHOUT_DYNAMIC_UPDATE); - runReadUnigramsAndBigramsTests(results, BinaryDictUtils.USE_BYTE_ARRAY, - BinaryDictUtils.VERSION3_WITH_DYNAMIC_UPDATE); - runReadUnigramsAndBigramsTests(results, BinaryDictUtils.USE_BYTE_ARRAY, - BinaryDictUtils.VERSION4_WITHOUT_DYNAMIC_UPDATE); + BinaryDictUtils.VERSION2_OPTIONS); runReadUnigramsAndBigramsTests(results, BinaryDictUtils.USE_BYTE_ARRAY, - BinaryDictUtils.VERSION4_WITH_DYNAMIC_UPDATE); + BinaryDictUtils.VERSION4_OPTIONS_WITHOUT_TIMESTAMP); runReadUnigramsAndBigramsTests(results, BinaryDictUtils.USE_BYTE_ARRAY, - BinaryDictUtils.VERSION4_WITH_DYNAMIC_UPDATE_AND_TIMESTAMP); + BinaryDictUtils.VERSION4_OPTIONS_WITH_TIMESTAMP); for (final String result : results) { Log.d(TAG, result); @@ -612,29 +576,19 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase { public void testGetTerminalPosition() { final ArrayList<String> results = CollectionUtils.newArrayList(); - runGetTerminalPositionTests(BinaryDictUtils.USE_BYTE_ARRAY, BinaryDictUtils.VERSION2); runGetTerminalPositionTests(BinaryDictUtils.USE_BYTE_ARRAY, - BinaryDictUtils.VERSION3_WITHOUT_DYNAMIC_UPDATE); + BinaryDictUtils.VERSION2_OPTIONS); runGetTerminalPositionTests(BinaryDictUtils.USE_BYTE_ARRAY, - BinaryDictUtils.VERSION3_WITH_DYNAMIC_UPDATE); + BinaryDictUtils.VERSION4_OPTIONS_WITHOUT_TIMESTAMP); runGetTerminalPositionTests(BinaryDictUtils.USE_BYTE_ARRAY, - BinaryDictUtils.VERSION4_WITHOUT_DYNAMIC_UPDATE); - runGetTerminalPositionTests(BinaryDictUtils.USE_BYTE_ARRAY, - BinaryDictUtils.VERSION4_WITH_DYNAMIC_UPDATE); - runGetTerminalPositionTests(BinaryDictUtils.USE_BYTE_ARRAY, - BinaryDictUtils.VERSION4_WITH_DYNAMIC_UPDATE_AND_TIMESTAMP); + BinaryDictUtils.VERSION4_OPTIONS_WITH_TIMESTAMP); - runGetTerminalPositionTests(BinaryDictUtils.USE_BYTE_BUFFER, BinaryDictUtils.VERSION2); - runGetTerminalPositionTests(BinaryDictUtils.USE_BYTE_BUFFER, - BinaryDictUtils.VERSION3_WITHOUT_DYNAMIC_UPDATE); - runGetTerminalPositionTests(BinaryDictUtils.USE_BYTE_BUFFER, - BinaryDictUtils.VERSION3_WITH_DYNAMIC_UPDATE); runGetTerminalPositionTests(BinaryDictUtils.USE_BYTE_BUFFER, - BinaryDictUtils.VERSION4_WITHOUT_DYNAMIC_UPDATE); + BinaryDictUtils.VERSION2_OPTIONS); runGetTerminalPositionTests(BinaryDictUtils.USE_BYTE_BUFFER, - BinaryDictUtils.VERSION4_WITH_DYNAMIC_UPDATE); + BinaryDictUtils.VERSION4_OPTIONS_WITHOUT_TIMESTAMP); runGetTerminalPositionTests(BinaryDictUtils.USE_BYTE_BUFFER, - BinaryDictUtils.VERSION4_WITH_DYNAMIC_UPDATE_AND_TIMESTAMP); + BinaryDictUtils.VERSION4_OPTIONS_WITH_TIMESTAMP); for (final String result : results) { Log.d(TAG, result); @@ -668,7 +622,7 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase { } public void testDeleteWord() throws IOException, UnsupportedFormatException { - runTestDeleteWord(BinaryDictUtils.VERSION3_WITH_DYNAMIC_UPDATE); - runTestDeleteWord(BinaryDictUtils.VERSION4_WITH_DYNAMIC_UPDATE); + runTestDeleteWord(BinaryDictUtils.VERSION4_OPTIONS_WITHOUT_TIMESTAMP); + runTestDeleteWord(BinaryDictUtils.VERSION4_OPTIONS_WITH_TIMESTAMP); } } diff --git a/tests/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtilsTests.java b/tests/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtilsTests.java index 308919499..9ed50c4b3 100644 --- a/tests/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtilsTests.java +++ b/tests/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtilsTests.java @@ -103,7 +103,7 @@ public class BinaryDictIOUtilsTests extends AndroidTestCase { Log.d(TAG, " end address = " + info.mEndAddress); } - private static void printNode(final Ver3DictDecoder dictDecoder, + private static void printNode(final Ver2DictDecoder dictDecoder, final FormatSpec.FormatOptions formatOptions) { final DictBuffer dictBuffer = dictDecoder.getDictBuffer(); Log.d(TAG, "Node at " + dictBuffer.position()); @@ -114,14 +114,14 @@ public class BinaryDictIOUtilsTests extends AndroidTestCase { formatOptions); printPtNode(currentInfo); } - if (formatOptions.mSupportsDynamicUpdate) { + if (formatOptions.supportsDynamicUpdate()) { final int forwardLinkAddress = dictBuffer.readUnsignedInt24(); Log.d(TAG, " forwardLinkAddress = " + forwardLinkAddress); } } @SuppressWarnings("unused") - private static void printBinaryFile(final Ver3DictDecoder dictDecoder) + private static void printBinaryFile(final Ver2DictDecoder dictDecoder) throws IOException, UnsupportedFormatException { final FileHeader fileHeader = dictDecoder.readHeader(); final DictBuffer dictBuffer = dictDecoder.getDictBuffer(); @@ -237,8 +237,7 @@ public class BinaryDictIOUtilsTests extends AndroidTestCase { dict.add("abcd", 10, null, false); try { - final DictEncoder dictEncoder = BinaryDictUtils.getDictEncoder(file, formatOptions, - getContext().getCacheDir()); + final DictEncoder dictEncoder = BinaryDictUtils.getDictEncoder(file, formatOptions); dictEncoder.writeDictionary(dict, formatOptions); } catch (IOException e) { fail("IOException while writing an initial dictionary : " + e); @@ -289,8 +288,8 @@ public class BinaryDictIOUtilsTests extends AndroidTestCase { } public void testInsertWord() { - runTestInsertWord(BinaryDictUtils.VERSION3_WITH_DYNAMIC_UPDATE); - runTestInsertWord(BinaryDictUtils.VERSION4_WITH_DYNAMIC_UPDATE); + runTestInsertWord(BinaryDictUtils.VERSION4_OPTIONS_WITHOUT_TIMESTAMP); + runTestInsertWord(BinaryDictUtils.VERSION4_OPTIONS_WITH_TIMESTAMP); } private void runTestInsertWordWithBigrams(final FormatOptions formatOptions) { @@ -306,8 +305,7 @@ public class BinaryDictIOUtilsTests extends AndroidTestCase { dict.add("efgh", 15, null, false); try { - final DictEncoder dictEncoder = BinaryDictUtils.getDictEncoder(file, formatOptions, - getContext().getCacheDir()); + final DictEncoder dictEncoder = BinaryDictUtils.getDictEncoder(file, formatOptions); dictEncoder.writeDictionary(dict, formatOptions); } catch (IOException e) { fail("IOException while writing an initial dictionary : " + e); @@ -329,8 +327,8 @@ public class BinaryDictIOUtilsTests extends AndroidTestCase { } public void testInsertWordWithBigrams() { - runTestInsertWordWithBigrams(BinaryDictUtils.VERSION3_WITH_DYNAMIC_UPDATE); - runTestInsertWordWithBigrams(BinaryDictUtils.VERSION4_WITH_DYNAMIC_UPDATE); + runTestInsertWordWithBigrams(BinaryDictUtils.VERSION4_OPTIONS_WITHOUT_TIMESTAMP); + runTestInsertWordWithBigrams(BinaryDictUtils.VERSION4_OPTIONS_WITH_TIMESTAMP); } private void runTestRandomWords(final FormatOptions formatOptions) { @@ -345,8 +343,7 @@ public class BinaryDictIOUtilsTests extends AndroidTestCase { dict.add("initial", 10, null, false); try { - final DictEncoder dictEncoder = BinaryDictUtils.getDictEncoder(file, formatOptions, - getContext().getCacheDir()); + final DictEncoder dictEncoder = BinaryDictUtils.getDictEncoder(file, formatOptions); dictEncoder.writeDictionary(dict, formatOptions); } catch (IOException e) { assertTrue(false); @@ -377,7 +374,7 @@ public class BinaryDictIOUtilsTests extends AndroidTestCase { } public void testRandomWords() { - runTestRandomWords(BinaryDictUtils.VERSION3_WITH_DYNAMIC_UPDATE); - runTestRandomWords(BinaryDictUtils.VERSION4_WITH_DYNAMIC_UPDATE); + runTestRandomWords(BinaryDictUtils.VERSION4_OPTIONS_WITHOUT_TIMESTAMP); + runTestRandomWords(BinaryDictUtils.VERSION4_OPTIONS_WITH_TIMESTAMP); } } diff --git a/tests/src/com/android/inputmethod/latin/makedict/BinaryDictUtils.java b/tests/src/com/android/inputmethod/latin/makedict/BinaryDictUtils.java index ad17a7118..67d77e05a 100644 --- a/tests/src/com/android/inputmethod/latin/makedict/BinaryDictUtils.java +++ b/tests/src/com/android/inputmethod/latin/makedict/BinaryDictUtils.java @@ -29,23 +29,15 @@ public class BinaryDictUtils { public static final String TEST_DICT_FILE_EXTENSION = ".testDict"; - public static final FormatSpec.FormatOptions VERSION2 = + public static final FormatSpec.FormatOptions VERSION2_OPTIONS = new FormatSpec.FormatOptions(FormatSpec.VERSION2); - public static final FormatSpec.FormatOptions VERSION3_WITHOUT_DYNAMIC_UPDATE = - new FormatSpec.FormatOptions(FormatSpec.VERSION3, false /* supportsDynamicUpdate */); - public static final FormatSpec.FormatOptions VERSION3_WITH_DYNAMIC_UPDATE = - new FormatSpec.FormatOptions(FormatSpec.VERSION3, true /* supportsDynamicUpdate */); - public static final FormatSpec.FormatOptions VERSION4_WITHOUT_DYNAMIC_UPDATE = - new FormatSpec.FormatOptions(FormatSpec.VERSION4, false /* supportsDynamicUpdate */); - public static final FormatSpec.FormatOptions VERSION4_WITH_DYNAMIC_UPDATE = - new FormatSpec.FormatOptions(FormatSpec.VERSION4, true /* supportsDynamicUpdate */); - public static final FormatSpec.FormatOptions VERSION4_WITH_DYNAMIC_UPDATE_AND_TIMESTAMP = - new FormatSpec.FormatOptions(FormatSpec.VERSION4, true /* supportsDynamicUpdate */, - true /* hasTimestamp */); + public static final FormatSpec.FormatOptions VERSION4_OPTIONS_WITHOUT_TIMESTAMP = + new FormatSpec.FormatOptions(FormatSpec.VERSION4, false /* hasTimestamp */); + public static final FormatSpec.FormatOptions VERSION4_OPTIONS_WITH_TIMESTAMP = + new FormatSpec.FormatOptions(FormatSpec.VERSION4, true /* hasTimestamp */); public static DictionaryOptions makeDictionaryOptions(final String id, final String version) { - final DictionaryOptions options = new DictionaryOptions(new HashMap<String, String>(), - false /* germanUmlautProcessing */, false /* frenchLigatureProcessing */); + final DictionaryOptions options = new DictionaryOptions(new HashMap<String, String>()); options.mAttributes.put(FileHeader.DICTIONARY_LOCALE_ATTRIBUTE, "en_US"); options.mAttributes.put(FileHeader.DICTIONARY_ID_ATTRIBUTE, id); options.mAttributes.put(FileHeader.DICTIONARY_VERSION_ATTRIBUTE, version); @@ -54,8 +46,7 @@ public class BinaryDictUtils { public static File getDictFile(final String name, final String version, final FormatOptions formatOptions, final File directory) { - if (formatOptions.mVersion == FormatSpec.VERSION2 - || formatOptions.mVersion == FormatSpec.VERSION3) { + if (formatOptions.mVersion == FormatSpec.VERSION2) { return new File(directory, name + "." + version + TEST_DICT_FILE_EXTENSION); } else if (formatOptions.mVersion == FormatSpec.VERSION4) { return new File(directory, name + "." + version); @@ -65,13 +56,14 @@ public class BinaryDictUtils { } } - public static DictEncoder getDictEncoder(final File file, final FormatOptions formatOptions, - final File cacheDir) { + public static DictEncoder getDictEncoder(final File file, final FormatOptions formatOptions) { if (formatOptions.mVersion == FormatSpec.VERSION4) { - return new Ver4DictEncoder(cacheDir); - } else if (formatOptions.mVersion == FormatSpec.VERSION3 - || formatOptions.mVersion == FormatSpec.VERSION2) { - return new Ver3DictEncoder(file); + if (!file.isDirectory()) { + file.mkdir(); + } + return new Ver4DictEncoder(file); + } else if (formatOptions.mVersion == FormatSpec.VERSION2) { + return new Ver2DictEncoder(file); } else { throw new RuntimeException("The format option has a wrong version : " + formatOptions.mVersion); @@ -82,8 +74,6 @@ public class BinaryDictUtils { throws UnsupportedFormatException { if (formatOptions.mVersion == FormatSpec.VERSION4) { return new Ver4DictUpdater(file, DictDecoder.USE_WRITABLE_BYTEBUFFER); - } else if (formatOptions.mVersion == FormatSpec.VERSION3) { - return new Ver3DictUpdater(file, DictDecoder.USE_WRITABLE_BYTEBUFFER); } else { throw new UnsupportedFormatException("The format option has a wrong version : " + formatOptions.mVersion); diff --git a/tests/src/com/android/inputmethod/latin/makedict/Ver3DictDecoderTests.java b/tests/src/com/android/inputmethod/latin/makedict/Ver2DictDecoderTests.java index 9611599b9..a85753e6b 100644 --- a/tests/src/com/android/inputmethod/latin/makedict/Ver3DictDecoderTests.java +++ b/tests/src/com/android/inputmethod/latin/makedict/Ver2DictDecoderTests.java @@ -32,10 +32,10 @@ import java.io.FileOutputStream; import java.io.IOException; /** - * Unit tests for Ver3DictDecoder + * Unit tests for Ver2DictDecoder */ -public class Ver3DictDecoderTests extends AndroidTestCase { - private static final String TAG = Ver3DictDecoderTests.class.getSimpleName(); +public class Ver2DictDecoderTests extends AndroidTestCase { + private static final String TAG = Ver2DictDecoderTests.class.getSimpleName(); private final byte[] data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; @@ -68,7 +68,7 @@ public class Ver3DictDecoderTests extends AndroidTestCase { } assertNotNull(testFile); - final Ver3DictDecoder dictDecoder = new Ver3DictDecoder(testFile, factory); + final Ver2DictDecoder dictDecoder = new Ver2DictDecoder(testFile, factory); try { dictDecoder.openDictBuffer(); } catch (Exception e) { @@ -110,7 +110,7 @@ public class Ver3DictDecoderTests extends AndroidTestCase { Log.e(TAG, "IOException while the creating temporary file", e); } - final Ver3DictDecoder dictDecoder = new Ver3DictDecoder(testFile, factory); + final Ver2DictDecoder dictDecoder = new Ver2DictDecoder(testFile, factory); // the default return value of getBuffer() must be null. assertNull("the default return value of getBuffer() is not null", diff --git a/tests/src/com/android/inputmethod/latin/utils/ForgettingCurveTests.java b/tests/src/com/android/inputmethod/latin/utils/ForgettingCurveTests.java deleted file mode 100644 index 823bd5d7d..000000000 --- a/tests/src/com/android/inputmethod/latin/utils/ForgettingCurveTests.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (C) 2012 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.utils; - -import android.test.AndroidTestCase; -import android.test.suitebuilder.annotation.SmallTest; - -@SmallTest -public class ForgettingCurveTests extends AndroidTestCase { - public void testFcToFreq() { - for (int i = 0; i < Byte.MAX_VALUE; ++i) { - final byte fc = (byte)i; - final int e = UserHistoryForgettingCurveUtils.fcToElapsedTime(fc); - final int c = UserHistoryForgettingCurveUtils.fcToCount(fc); - final int l = UserHistoryForgettingCurveUtils.fcToLevel(fc); - final byte fc2 = UserHistoryForgettingCurveUtils.calcFc(e, c, l); - assertEquals(fc, fc2); - } - byte fc = 0; - int l; - for (int i = 0; i < 4; ++i) { - for (int j = 0; j < (UserHistoryForgettingCurveUtils.COUNT_MAX + 1); ++j) { - fc = UserHistoryForgettingCurveUtils.pushCount(fc, true); - } - l = UserHistoryForgettingCurveUtils.fcToLevel(fc); - assertEquals(l, Math.max(1, Math.min(i + 1, 3))); - } - fc = 0; - for (int i = 0; i < 4; ++i) { - for (int j = 0; j < (UserHistoryForgettingCurveUtils.COUNT_MAX + 1); ++j) { - fc = UserHistoryForgettingCurveUtils.pushCount(fc, false); - } - l = UserHistoryForgettingCurveUtils.fcToLevel(fc); - assertEquals(l, Math.min(i + 1, 3)); - } - for (int i = 0; i < 4; ++i) { - for (int j = 0; j < (UserHistoryForgettingCurveUtils.ELAPSED_TIME_MAX + 1); ++j) { - fc = UserHistoryForgettingCurveUtils.pushElapsedTime(fc); - } - l = UserHistoryForgettingCurveUtils.fcToLevel(fc); - assertEquals(l, Math.max(0, 2 - i)); - } - } -} diff --git a/tests/src/com/android/inputmethod/latin/utils/UserHistoryDictIOUtilsTests.java b/tests/src/com/android/inputmethod/latin/utils/UserHistoryDictIOUtilsTests.java index fc921b4fd..ae08b49d7 100644 --- a/tests/src/com/android/inputmethod/latin/utils/UserHistoryDictIOUtilsTests.java +++ b/tests/src/com/android/inputmethod/latin/utils/UserHistoryDictIOUtilsTests.java @@ -28,8 +28,8 @@ import com.android.inputmethod.latin.makedict.FormatSpec.FileHeader; import com.android.inputmethod.latin.makedict.FusionDictionary; import com.android.inputmethod.latin.makedict.FusionDictionary.PtNode; import com.android.inputmethod.latin.makedict.UnsupportedFormatException; -import com.android.inputmethod.latin.makedict.Ver3DictDecoder; -import com.android.inputmethod.latin.makedict.Ver3DictEncoder; +import com.android.inputmethod.latin.makedict.Ver2DictDecoder; +import com.android.inputmethod.latin.makedict.Ver2DictEncoder; import com.android.inputmethod.latin.personalization.UserHistoryDictionaryBigramList; import com.android.inputmethod.latin.utils.UserHistoryDictIOUtils.BigramDictionaryInterface; import com.android.inputmethod.latin.utils.UserHistoryDictIOUtils.OnAddWordListener; @@ -146,7 +146,7 @@ public class UserHistoryDictIOUtilsTests extends AndroidTestCase private void writeDictToFile(final File file, final UserHistoryDictionaryBigramList bigramList) { - final DictEncoder dictEncoder = new Ver3DictEncoder(file); + final DictEncoder dictEncoder = new Ver2DictEncoder(file); UserHistoryDictIOUtils.writeDictionary(dictEncoder, this, bigramList, FORMAT_OPTIONS, HEADER_OPTIONS); } diff --git a/tools/dicttool/Android.mk b/tools/dicttool/Android.mk index 895e4a231..95afb4cc1 100644 --- a/tools/dicttool/Android.mk +++ b/tools/dicttool/Android.mk @@ -27,11 +27,28 @@ LATINIME_BASE_SOURCE_DIRECTORY := $(LATINIME_LOCAL_DIR)/java/src/com/android/inp LATINIME_ANNOTATIONS_SOURCE_DIRECTORY := $(LATINIME_BASE_SOURCE_DIRECTORY)/annotations LATINIME_CORE_SOURCE_DIRECTORY := $(LATINIME_BASE_SOURCE_DIRECTORY)/latin MAKEDICT_CORE_SOURCE_DIRECTORY := $(LATINIME_CORE_SOURCE_DIRECTORY)/makedict + +# Dependencies for Dicttool. Most of these files are needed by BinaryDictionary.java. Note that +# a significant part of the dependencies are mocked in the compat/ directory, with empty or +# nearly-empty implementations, for parts that we don't use in Dicttool. USED_TARGETTED_UTILS := \ + $(LATINIME_CORE_SOURCE_DIRECTORY)/BinaryDictionary.java \ + $(LATINIME_CORE_SOURCE_DIRECTORY)/DicTraverseSession.java \ + $(LATINIME_CORE_SOURCE_DIRECTORY)/Dictionary.java \ + $(LATINIME_CORE_SOURCE_DIRECTORY)/InputPointers.java \ + $(LATINIME_CORE_SOURCE_DIRECTORY)/LastComposedWord.java \ + $(LATINIME_CORE_SOURCE_DIRECTORY)/LatinImeLogger.java \ + $(LATINIME_CORE_SOURCE_DIRECTORY)/SuggestedWords.java \ + $(LATINIME_CORE_SOURCE_DIRECTORY)/WordComposer.java \ + $(LATINIME_CORE_SOURCE_DIRECTORY)/settings/NativeSuggestOptions.java \ $(LATINIME_CORE_SOURCE_DIRECTORY)/utils/ByteArrayDictBuffer.java \ $(LATINIME_CORE_SOURCE_DIRECTORY)/utils/CollectionUtils.java \ $(LATINIME_CORE_SOURCE_DIRECTORY)/utils/FileUtils.java \ - $(LATINIME_CORE_SOURCE_DIRECTORY)/utils/JniUtils.java + $(LATINIME_CORE_SOURCE_DIRECTORY)/utils/JniUtils.java \ + $(LATINIME_CORE_SOURCE_DIRECTORY)/utils/LocaleUtils.java \ + $(LATINIME_CORE_SOURCE_DIRECTORY)/utils/ResizableIntArray.java \ + $(LATINIME_CORE_SOURCE_DIRECTORY)/utils/StringUtils.java \ + $(LATINIME_CORE_SOURCE_DIRECTORY)/utils/UnigramProperty.java DICTTOOL_ONDEVICE_TESTS_DIRECTORY := \ $(LATINIME_LOCAL_DIR)/tests/src/com/android/inputmethod/latin/makedict/ diff --git a/tools/dicttool/NativeLib.mk b/tools/dicttool/NativeLib.mk index a3d3c0295..05e5841d3 100644 --- a/tools/dicttool/NativeLib.mk +++ b/tools/dicttool/NativeLib.mk @@ -20,12 +20,17 @@ include $(CLEAR_VARS) LATINIME_DIR_RELATIVE_TO_DICTTOOL := ../.. +ifeq ($(FLAG_DBG), true) + $(warning Making debug version of native library) + LOCAL_CFLAGS += -DFLAG_DBG -funwind-tables -fno-inline +endif #FLAG_DBG + ifneq ($(strip $(HOST_JDK_IS_64BIT_VERSION)),) LOCAL_CFLAGS += -m64 LOCAL_LDFLAGS += -m64 endif #HOST_JDK_IS_64BIT_VERSION -LOCAL_CFLAGS += -DHOST_TOOL -fPIC +LOCAL_CFLAGS += -DHOST_TOOL -fPIC -Wno-deprecated LOCAL_NO_DEFAULT_COMPILER_FLAGS := true LATINIME_NATIVE_JNI_DIR := $(LATINIME_DIR_RELATIVE_TO_DICTTOOL)/native/jni @@ -33,11 +38,7 @@ LATINIME_NATIVE_SRC_DIR := $(LATINIME_DIR_RELATIVE_TO_DICTTOOL)/native/jni/src LOCAL_C_INCLUDES := $(LOCAL_PATH)/$(LATINIME_NATIVE_SRC_DIR) # Used in jni_common.cpp to avoid registering useless methods. -LATIN_IME_JNI_SRC_FILES := \ - com_android_inputmethod_latin_makedict_Ver3DictDecoder.cpp \ - jni_common.cpp - -LATIN_IME_CORE_SRC_FILES := +include $(LOCAL_PATH)/$(LATINIME_NATIVE_JNI_DIR)/NativeFileList.mk LOCAL_SRC_FILES := \ $(addprefix $(LATINIME_NATIVE_JNI_DIR)/, $(LATIN_IME_JNI_SRC_FILES)) \ @@ -48,4 +49,5 @@ LOCAL_MODULE := $(LATINIME_HOST_NATIVE_LIBNAME) include $(BUILD_HOST_SHARED_LIBRARY) # Clear our private variables +include $(LOCAL_PATH)/$(LATINIME_NATIVE_JNI_DIR)/CleanupNativeFileList.mk LATINIME_DIR_RELATIVE_TO_DICTTOOL := ../.. diff --git a/native/jni/com_android_inputmethod_latin_makedict_Ver3DictDecoder.h b/tools/dicttool/compat/android/content/SharedPreferences.java index 07e80f1d8..cfeb1532d 100644 --- a/native/jni/com_android_inputmethod_latin_makedict_Ver3DictDecoder.h +++ b/tools/dicttool/compat/android/content/SharedPreferences.java @@ -14,12 +14,10 @@ * limitations under the License. */ -#ifndef _COM_ANDROID_INPUTMETHOD_LATIN_MAKEDICT_VER3DICTDECODER_H -#define _COM_ANDROID_INPUTMETHOD_LATIN_MAKEDICT_VER3DICTDECODER_H +package android.content; -#include "jni.h" - -namespace latinime { -int register_Ver3DictDecoder(JNIEnv *env); -} // namespace latinime -#endif // _COM_ANDROID_INPUTMETHOD_LATIN_MAKEDICT_VER3DICTDECODER_H +public class SharedPreferences { + public interface OnSharedPreferenceChangeListener { + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key); + } +} diff --git a/tools/dicttool/compat/android/graphics/Rect.java b/tools/dicttool/compat/android/graphics/Rect.java new file mode 100644 index 000000000..c7b61d759 --- /dev/null +++ b/tools/dicttool/compat/android/graphics/Rect.java @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2013 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 android.graphics; + +public class Rect { +} diff --git a/tools/dicttool/compat/android/text/TextUtils.java b/tools/dicttool/compat/android/text/TextUtils.java new file mode 100644 index 000000000..5a94b7d4c --- /dev/null +++ b/tools/dicttool/compat/android/text/TextUtils.java @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2013 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 android.text; + +public class TextUtils { + private TextUtils() { /* cannot be instantiated */ } + + /** + * Returns true if the string is null or 0-length. + * @param str the string to be examined + * @return true if str is null or zero length + */ + public static boolean isEmpty(CharSequence str) { + if (str == null || str.length() == 0) + return true; + else + return false; + } + + /** + * Returns true if a and b are equal, including if they are both null. + * <p><i>Note: In platform versions 1.1 and earlier, this method only worked well if + * both the arguments were instances of String.</i></p> + * @param a first CharSequence to check + * @param b second CharSequence to check + * @return true if a and b are equal + */ + public static boolean equals(CharSequence a, CharSequence b) { + if (a == b) return true; + int length; + if (a != null && b != null && (length = a.length()) == b.length()) { + if (a instanceof String && b instanceof String) { + return a.equals(b); + } else { + for (int i = 0; i < length; i++) { + if (a.charAt(i) != b.charAt(i)) return false; + } + return true; + } + } + return false; + } + + /** + * Returns list of multiple {@link CharSequence} joined into a single + * {@link CharSequence} separated by localized delimiter such as ", ". + * + * @hide + */ + public static CharSequence join(Iterable<CharSequence> list) { + final CharSequence delimiter = ", "; + return join(delimiter, list); + } + + /** + * Returns a string containing the tokens joined by delimiters. + * @param tokens an array objects to be joined. Strings will be formed from + * the objects by calling object.toString(). + */ + public static String join(CharSequence delimiter, Object[] tokens) { + StringBuilder sb = new StringBuilder(); + boolean firstTime = true; + for (Object token: tokens) { + if (firstTime) { + firstTime = false; + } else { + sb.append(delimiter); + } + sb.append(token); + } + return sb.toString(); + } + + /** + * Returns a string containing the tokens joined by delimiters. + * @param tokens an array objects to be joined. Strings will be formed from + * the objects by calling object.toString(). + */ + public static String join(CharSequence delimiter, Iterable tokens) { + StringBuilder sb = new StringBuilder(); + boolean firstTime = true; + for (Object token: tokens) { + if (firstTime) { + firstTime = false; + } else { + sb.append(delimiter); + } + sb.append(token); + } + return sb.toString(); + } + +} diff --git a/tools/dicttool/compat/android/util/Log.java b/tools/dicttool/compat/android/util/Log.java index b3b6dd847..9410e74a2 100644 --- a/tools/dicttool/compat/android/util/Log.java +++ b/tools/dicttool/compat/android/util/Log.java @@ -25,13 +25,19 @@ public class Log { public static void d(final String tag, final String message) { System.out.println(tag + " : " + message); } - public static void d(final String tag, final String message, final Throwable e) { - System.out.println(tag + " : " + message + " : " + e); + public static void d(final String tag, final String message, final Throwable t) { + System.out.println(tag + " : " + message + " : " + t); } public static void e(final String tag, final String message) { d(tag, message); } - public static void e(final String tag, final String message, final Throwable e) { - d(tag, message, e); + public static void e(final String tag, final String message, final Throwable t) { + d(tag, message, t); + } + public static void w(final String tag, final String message) { + d(tag, message); + } + public static void w(final String tag, final String message, final Throwable t) { + d(tag, message, t); } } diff --git a/tools/dicttool/compat/android/view/inputmethod/CompletionInfo.java b/tools/dicttool/compat/android/view/inputmethod/CompletionInfo.java new file mode 100644 index 000000000..fbce72556 --- /dev/null +++ b/tools/dicttool/compat/android/view/inputmethod/CompletionInfo.java @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2013 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 android.view.inputmethod; + +public class CompletionInfo { + public final String getText() { return ""; } +} diff --git a/tools/dicttool/compat/android/view/inputmethod/EditorInfo.java b/tools/dicttool/compat/android/view/inputmethod/EditorInfo.java new file mode 100644 index 000000000..9c7118118 --- /dev/null +++ b/tools/dicttool/compat/android/view/inputmethod/EditorInfo.java @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2013 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 android.view.inputmethod; + +public class EditorInfo { +} diff --git a/tools/dicttool/compat/com/android/inputmethod/keyboard/Key.java b/tools/dicttool/compat/com/android/inputmethod/keyboard/Key.java new file mode 100644 index 000000000..1e63bb526 --- /dev/null +++ b/tools/dicttool/compat/com/android/inputmethod/keyboard/Key.java @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2013 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.keyboard; + +public class Key { + public final int getX() { return 0; } + public final int getY() { return 0; } + public final int getWidth() { return 0; } + public final int getHeight() { return 0; } +} diff --git a/tools/dicttool/compat/com/android/inputmethod/keyboard/Keyboard.java b/tools/dicttool/compat/com/android/inputmethod/keyboard/Keyboard.java new file mode 100644 index 000000000..61b209f4d --- /dev/null +++ b/tools/dicttool/compat/com/android/inputmethod/keyboard/Keyboard.java @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2013 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.keyboard; + +public class Keyboard { + private final Key KEY = new Key(); + public final Key getKey(final int i) { return KEY; } +} diff --git a/tools/dicttool/compat/com/android/inputmethod/keyboard/ProximityInfo.java b/tools/dicttool/compat/com/android/inputmethod/keyboard/ProximityInfo.java new file mode 100644 index 000000000..561b6637c --- /dev/null +++ b/tools/dicttool/compat/com/android/inputmethod/keyboard/ProximityInfo.java @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2013 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.keyboard; + +public class ProximityInfo { + public long getNativeProximityInfo() { return 0l; } + private static native long setProximityInfoNative(String locale, + int displayWidth, int displayHeight, int gridWidth, int gridHeight, + int mostCommonKeyWidth, int mostCommonKeyHeight, int[] proximityCharsArray, + int keyCount, int[] keyXCoordinates, int[] keyYCoordinates, int[] keyWidths, + int[] keyHeights, int[] keyCharCodes, float[] sweetSpotCenterXs, + float[] sweetSpotCenterYs, float[] sweetSpotRadii); + private static native void releaseProximityInfoNative(long nativeProximityInfo); +} diff --git a/tools/dicttool/compat/com/android/inputmethod/latin/LatinIME.java b/tools/dicttool/compat/com/android/inputmethod/latin/LatinIME.java new file mode 100644 index 000000000..e7aa340fb --- /dev/null +++ b/tools/dicttool/compat/com/android/inputmethod/latin/LatinIME.java @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2013 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; + +public class LatinIME { +} diff --git a/tools/dicttool/compat/com/android/inputmethod/latin/settings/AdditionalFeaturesSettingUtils.java b/tools/dicttool/compat/com/android/inputmethod/latin/settings/AdditionalFeaturesSettingUtils.java new file mode 100644 index 000000000..6a430d57d --- /dev/null +++ b/tools/dicttool/compat/com/android/inputmethod/latin/settings/AdditionalFeaturesSettingUtils.java @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2013 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.settings; + +public class AdditionalFeaturesSettingUtils { + public static final int ADDITIONAL_FEATURES_SETTINGS_SIZE = 0; +} diff --git a/tools/dicttool/compat/com/android/inputmethod/latin/settings/SettingsValues.java b/tools/dicttool/compat/com/android/inputmethod/latin/settings/SettingsValues.java new file mode 100644 index 000000000..0a84cdeee --- /dev/null +++ b/tools/dicttool/compat/com/android/inputmethod/latin/settings/SettingsValues.java @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2013 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.settings; + +public class SettingsValues { + public boolean isWordCodePoint(final int code) { + return Character.isLetter(code); + } +} diff --git a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/CombinedInputOutput.java b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/CombinedInputOutput.java index 4b6716936..16f82dafd 100644 --- a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/CombinedInputOutput.java +++ b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/CombinedInputOutput.java @@ -50,8 +50,6 @@ public class CombinedInputOutput { private static final String NOT_A_WORD_TAG = "not_a_word"; private static final String WHITELIST_TAG = "whitelist"; private static final String OPTIONS_TAG = "options"; - private static final String GERMAN_UMLAUT_PROCESSING_OPTION = "german_umlaut_processing"; - private static final String FRENCH_LIGATURE_PROCESSING_OPTION = "french_ligature_processing"; private static final String COMMENT_LINE_STARTER = "#"; /** @@ -112,13 +110,9 @@ public class CombinedInputOutput { attributes.put(keyValue[0], keyValue[1]); } - final boolean processUmlauts = - GERMAN_UMLAUT_PROCESSING_OPTION.equals(attributes.get(OPTIONS_TAG)); - final boolean processLigatures = - FRENCH_LIGATURE_PROCESSING_OPTION.equals(attributes.get(OPTIONS_TAG)); attributes.remove(OPTIONS_TAG); - final FusionDictionary dict = new FusionDictionary(new PtNodeArray(), new DictionaryOptions( - attributes, processUmlauts, processLigatures)); + final FusionDictionary dict = + new FusionDictionary(new PtNodeArray(), new DictionaryOptions(attributes)); String line; String word = null; @@ -216,11 +210,6 @@ public class CombinedInputOutput { destination.write(options.get(DICTIONARY_TAG)); options.remove(DICTIONARY_TAG); } - if (dict.mOptions.mGermanUmlautProcessing) { - destination.write("," + OPTIONS_TAG + "=" + GERMAN_UMLAUT_PROCESSING_OPTION); - } else if (dict.mOptions.mFrenchLigatureProcessing) { - destination.write("," + OPTIONS_TAG + "=" + FRENCH_LIGATURE_PROCESSING_OPTION); - } for (final String key : dict.mOptions.mAttributes.keySet()) { final String value = dict.mOptions.mAttributes.get(key); destination.write("," + key + "=" + value); diff --git a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/DictionaryMaker.java b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/DictionaryMaker.java index b3543a0c2..143bce5ac 100644 --- a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/DictionaryMaker.java +++ b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/DictionaryMaker.java @@ -23,7 +23,7 @@ import com.android.inputmethod.latin.makedict.FormatSpec; import com.android.inputmethod.latin.makedict.FusionDictionary; import com.android.inputmethod.latin.makedict.MakedictLog; import com.android.inputmethod.latin.makedict.UnsupportedFormatException; -import com.android.inputmethod.latin.makedict.Ver3DictEncoder; +import com.android.inputmethod.latin.makedict.Ver2DictEncoder; import com.android.inputmethod.latin.makedict.Ver4DictEncoder; import java.io.BufferedWriter; @@ -46,7 +46,6 @@ public class DictionaryMaker { static class Arguments { private static final String OPTION_VERSION_2 = "-2"; - private static final String OPTION_VERSION_3 = "-3"; private static final String OPTION_VERSION_4 = "-4"; private static final String OPTION_INPUT_SOURCE = "-s"; private static final String OPTION_INPUT_BIGRAM_XML = "-b"; @@ -158,8 +157,6 @@ public class DictionaryMaker { if (arg.charAt(0) == '-') { if (OPTION_VERSION_2.equals(arg)) { // Do nothing, this is the default - } else if (OPTION_VERSION_3.equals(arg)) { - outputBinaryFormatVersion = FormatSpec.VERSION3; } else if (OPTION_VERSION_4.equals(arg)) { outputBinaryFormatVersion = FormatSpec.VERSION4; } else if (OPTION_HELP.equals(arg)) { @@ -361,7 +358,7 @@ public class DictionaryMaker { if (version == FormatSpec.VERSION4) { dictEncoder = new Ver4DictEncoder(outputFile); } else { - dictEncoder = new Ver3DictEncoder(outputFile); + dictEncoder = new Ver2DictEncoder(outputFile); } dictEncoder.writeDictionary(dict, formatOptions); } diff --git a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Diff.java b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Diff.java index 66fd084cd..7ac3c67a1 100644 --- a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Diff.java +++ b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Diff.java @@ -85,18 +85,6 @@ public class Diff extends Dicttool.Command { private static void diffHeaders(final FusionDictionary dict0, final FusionDictionary dict1) { boolean hasDifferences = false; - if (dict0.mOptions.mFrenchLigatureProcessing != dict1.mOptions.mFrenchLigatureProcessing) { - System.out.println(" French ligature processing : " - + dict0.mOptions.mFrenchLigatureProcessing + " <=> " - + dict1.mOptions.mFrenchLigatureProcessing); - hasDifferences = true; - } - else if (dict0.mOptions.mGermanUmlautProcessing != dict1.mOptions.mGermanUmlautProcessing) { - System.out.println(" German umlaut processing : " - + dict0.mOptions.mGermanUmlautProcessing + " <=> " - + dict1.mOptions.mGermanUmlautProcessing); - hasDifferences = true; - } final HashMap<String, String> options1 = new HashMap<String, String>(dict1.mOptions.mAttributes); for (final String optionKey : dict0.mOptions.mAttributes.keySet()) { diff --git a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/XmlDictInputOutput.java b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/XmlDictInputOutput.java index 4e99bf979..d226251c1 100644 --- a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/XmlDictInputOutput.java +++ b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/XmlDictInputOutput.java @@ -57,8 +57,6 @@ public class XmlDictInputOutput { private static final String NOT_A_WORD_ATTR = "not_a_word"; private static final String OPTIONS_KEY = "options"; - private static final String GERMAN_UMLAUT_PROCESSING_OPTION = "german_umlaut_processing"; - private static final String FRENCH_LIGATURE_PROCESSING_OPTION = "french_ligature_processing"; /** * SAX handler for a unigram XML file. @@ -120,12 +118,8 @@ public class XmlDictInputOutput { attributes.put(attrName, attrs.getValue(attrIndex)); } final String optionsString = attributes.get(OPTIONS_KEY); - final boolean processUmlauts = - GERMAN_UMLAUT_PROCESSING_OPTION.equals(optionsString); - final boolean processLigatures = - FRENCH_LIGATURE_PROCESSING_OPTION.equals(optionsString); mDictionary = new FusionDictionary(new PtNodeArray(), - new DictionaryOptions(attributes, processUmlauts, processLigatures)); + new DictionaryOptions(attributes)); } else { mState = UNKNOWN; } @@ -361,11 +355,6 @@ public class XmlDictInputOutput { // TODO: use an XMLSerializer if this gets big destination.write("<wordlist format=\"2\""); final HashMap<String, String> options = dict.mOptions.mAttributes; - if (dict.mOptions.mGermanUmlautProcessing) { - destination.write(" " + OPTIONS_KEY + "=\"" + GERMAN_UMLAUT_PROCESSING_OPTION + "\""); - } else if (dict.mOptions.mFrenchLigatureProcessing) { - destination.write(" " + OPTIONS_KEY + "=\"" + FRENCH_LIGATURE_PROCESSING_OPTION + "\""); - } for (final String key : dict.mOptions.mAttributes.keySet()) { final String value = dict.mOptions.mAttributes.get(key); destination.write(" " + key + "=\"" + value + "\""); diff --git a/tools/dicttool/tests/com/android/inputmethod/latin/dicttool/BinaryDictOffdeviceUtilsTests.java b/tools/dicttool/tests/com/android/inputmethod/latin/dicttool/BinaryDictOffdeviceUtilsTests.java index 1baeb7a47..9e397f19d 100644 --- a/tools/dicttool/tests/com/android/inputmethod/latin/dicttool/BinaryDictOffdeviceUtilsTests.java +++ b/tools/dicttool/tests/com/android/inputmethod/latin/dicttool/BinaryDictOffdeviceUtilsTests.java @@ -24,7 +24,7 @@ import com.android.inputmethod.latin.makedict.FusionDictionary; import com.android.inputmethod.latin.makedict.FusionDictionary.DictionaryOptions; import com.android.inputmethod.latin.makedict.FusionDictionary.PtNodeArray; import com.android.inputmethod.latin.makedict.UnsupportedFormatException; -import com.android.inputmethod.latin.makedict.Ver3DictEncoder; +import com.android.inputmethod.latin.makedict.Ver2DictEncoder; import junit.framework.TestCase; @@ -44,8 +44,7 @@ public class BinaryDictOffdeviceUtilsTests extends TestCase { public void testGetRawDictWorks() throws IOException, UnsupportedFormatException { // Create a thrice-compressed dictionary file. final FusionDictionary dict = new FusionDictionary(new PtNodeArray(), - new DictionaryOptions(new HashMap<String, String>(), - false /* germanUmlautProcessing */, false /* frenchLigatureProcessing */)); + new DictionaryOptions(new HashMap<String, String>())); dict.add("foo", TEST_FREQ, null, false /* isNotAWord */); dict.add("fta", 1, null, false /* isNotAWord */); dict.add("ftb", 1, null, false /* isNotAWord */); @@ -59,7 +58,7 @@ public class BinaryDictOffdeviceUtilsTests extends TestCase { Compress.getCompressedStream( Compress.getCompressedStream( new BufferedOutputStream(new FileOutputStream(dst))))); - final DictEncoder dictEncoder = new Ver3DictEncoder(out); + final DictEncoder dictEncoder = new Ver2DictEncoder(out); dictEncoder.writeDictionary(dict, new FormatOptions(2, false)); // Test for an actually compressed dictionary and its contents diff --git a/tools/dicttool/tests/com/android/inputmethod/latin/makedict/BinaryDictEncoderFlattenTreeTests.java b/tools/dicttool/tests/com/android/inputmethod/latin/makedict/BinaryDictEncoderFlattenTreeTests.java index 55058238c..c6e497615 100644 --- a/tools/dicttool/tests/com/android/inputmethod/latin/makedict/BinaryDictEncoderFlattenTreeTests.java +++ b/tools/dicttool/tests/com/android/inputmethod/latin/makedict/BinaryDictEncoderFlattenTreeTests.java @@ -32,8 +32,7 @@ public class BinaryDictEncoderFlattenTreeTests extends TestCase { // that it does not contain any duplicates. public void testFlattenNodes() { final FusionDictionary dict = new FusionDictionary(new PtNodeArray(), - new DictionaryOptions(new HashMap<String, String>(), - false /* germanUmlautProcessing */, false /* frenchLigatureProcessing */)); + new DictionaryOptions(new HashMap<String, String>())); dict.add("foo", 1, null, false /* isNotAWord */); dict.add("fta", 1, null, false /* isNotAWord */); dict.add("ftb", 1, null, false /* isNotAWord */); diff --git a/tools/dicttool/tests/com/android/inputmethod/latin/makedict/FusionDictionaryTest.java b/tools/dicttool/tests/com/android/inputmethod/latin/makedict/FusionDictionaryTest.java index 659650a05..76dadc25c 100644 --- a/tools/dicttool/tests/com/android/inputmethod/latin/makedict/FusionDictionaryTest.java +++ b/tools/dicttool/tests/com/android/inputmethod/latin/makedict/FusionDictionaryTest.java @@ -96,8 +96,7 @@ public class FusionDictionaryTest extends TestCase { // that it does not contain any duplicates. public void testFusion() { final FusionDictionary dict = new FusionDictionary(new PtNodeArray(), - new DictionaryOptions(new HashMap<String, String>(), - false /* germanUmlautProcessing */, false /* frenchLigatureProcessing */)); + new DictionaryOptions(new HashMap<String, String>())); final long time = System.currentTimeMillis(); prepare(time); for (int i = 0; i < sWords.size(); ++i) { diff --git a/tools/make-keyboard-text/res/values-az/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-az-rAZ/donottranslate-more-keys.xml index db1784c17..db1784c17 100644 --- a/tools/make-keyboard-text/res/values-az/donottranslate-more-keys.xml +++ b/tools/make-keyboard-text/res/values-az-rAZ/donottranslate-more-keys.xml diff --git a/tools/make-keyboard-text/res/values-ne/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-ne-rNP/donottranslate-more-keys.xml index 9205e5309..9205e5309 100644 --- a/tools/make-keyboard-text/res/values-ne/donottranslate-more-keys.xml +++ b/tools/make-keyboard-text/res/values-ne-rNP/donottranslate-more-keys.xml |