aboutsummaryrefslogtreecommitdiffstats
path: root/java/src/com/android/inputmethod/latin/BinaryDictionary.java
diff options
context:
space:
mode:
authorAmin Bandali <bandali@kelar.org>2024-12-16 21:45:41 -0500
committerAmin Bandali <bandali@kelar.org>2025-01-11 14:17:35 -0500
commite9a0e66716dab4dd3184d009d8920de1961efdfa (patch)
tree02dcc096643d74645bf28459c2834c3d4a2ad7f2 /java/src/com/android/inputmethod/latin/BinaryDictionary.java
parentfb3b9360d70596d7e921de8bf7d3ca99564a077e (diff)
downloadlatinime-e9a0e66716dab4dd3184d009d8920de1961efdfa.tar.gz
latinime-e9a0e66716dab4dd3184d009d8920de1961efdfa.tar.xz
latinime-e9a0e66716dab4dd3184d009d8920de1961efdfa.zip
Rename to Kelar Keyboard (org.kelar.inputmethod.latin)
Diffstat (limited to 'java/src/com/android/inputmethod/latin/BinaryDictionary.java')
-rw-r--r--java/src/com/android/inputmethod/latin/BinaryDictionary.java669
1 files changed, 0 insertions, 669 deletions
diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java
deleted file mode 100644
index 9a3ac674e..000000000
--- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java
+++ /dev/null
@@ -1,669 +0,0 @@
-/*
- * Copyright (C) 2008 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;
-
-import android.text.TextUtils;
-import android.util.Log;
-import android.util.SparseArray;
-
-import com.android.inputmethod.annotations.UsedForTesting;
-import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
-import com.android.inputmethod.latin.common.ComposedData;
-import com.android.inputmethod.latin.common.Constants;
-import com.android.inputmethod.latin.common.FileUtils;
-import com.android.inputmethod.latin.common.InputPointers;
-import com.android.inputmethod.latin.common.StringUtils;
-import com.android.inputmethod.latin.makedict.DictionaryHeader;
-import com.android.inputmethod.latin.makedict.FormatSpec;
-import com.android.inputmethod.latin.makedict.FormatSpec.DictionaryOptions;
-import com.android.inputmethod.latin.makedict.UnsupportedFormatException;
-import com.android.inputmethod.latin.makedict.WordProperty;
-import com.android.inputmethod.latin.settings.SettingsValuesForSuggestion;
-import com.android.inputmethod.latin.utils.BinaryDictionaryUtils;
-import com.android.inputmethod.latin.utils.JniUtils;
-import com.android.inputmethod.latin.utils.WordInputEventForPersonalization;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.Locale;
-import java.util.Map;
-
-import javax.annotation.Nonnull;
-
-/**
- * Implements a static, compacted, binary dictionary of standard words.
- */
-// TODO: All methods which should be locked need to have a suffix "Locked".
-public final class BinaryDictionary extends Dictionary {
- private static final String TAG = BinaryDictionary.class.getSimpleName();
-
- // The cutoff returned by native for auto-commit confidence.
- // Must be equal to CONFIDENCE_TO_AUTO_COMMIT in native/jni/src/defines.h
- private static final int CONFIDENCE_TO_AUTO_COMMIT = 1000000;
-
- public static final int DICTIONARY_MAX_WORD_LENGTH = 48;
- public static final int MAX_PREV_WORD_COUNT_FOR_N_GRAM = 3;
-
- @UsedForTesting
- public static final String UNIGRAM_COUNT_QUERY = "UNIGRAM_COUNT";
- @UsedForTesting
- public static final String BIGRAM_COUNT_QUERY = "BIGRAM_COUNT";
- @UsedForTesting
- public static final String MAX_UNIGRAM_COUNT_QUERY = "MAX_UNIGRAM_COUNT";
- @UsedForTesting
- public static final String MAX_BIGRAM_COUNT_QUERY = "MAX_BIGRAM_COUNT";
-
- public static final int NOT_A_VALID_TIMESTAMP = -1;
-
- // Format to get unigram flags from native side via getWordPropertyNative().
- private static final int FORMAT_WORD_PROPERTY_OUTPUT_FLAG_COUNT = 5;
- private static final int FORMAT_WORD_PROPERTY_IS_NOT_A_WORD_INDEX = 0;
- private static final int FORMAT_WORD_PROPERTY_IS_POSSIBLY_OFFENSIVE_INDEX = 1;
- private static final int FORMAT_WORD_PROPERTY_HAS_NGRAMS_INDEX = 2;
- private static final int FORMAT_WORD_PROPERTY_HAS_SHORTCUTS_INDEX = 3; // DEPRECATED
- private static final int FORMAT_WORD_PROPERTY_IS_BEGINNING_OF_SENTENCE_INDEX = 4;
-
- // Format to get probability and historical info from native side via getWordPropertyNative().
- public static final int FORMAT_WORD_PROPERTY_OUTPUT_PROBABILITY_INFO_COUNT = 4;
- public static final int FORMAT_WORD_PROPERTY_PROBABILITY_INDEX = 0;
- public static final int FORMAT_WORD_PROPERTY_TIMESTAMP_INDEX = 1;
- public static final int FORMAT_WORD_PROPERTY_LEVEL_INDEX = 2;
- public static final int FORMAT_WORD_PROPERTY_COUNT_INDEX = 3;
-
- public static final String DICT_FILE_NAME_SUFFIX_FOR_MIGRATION = ".migrate";
- public static final String DIR_NAME_SUFFIX_FOR_RECORD_MIGRATION = ".migrating";
-
- private long mNativeDict;
- private final long mDictSize;
- private final String mDictFilePath;
- private final boolean mUseFullEditDistance;
- private final boolean mIsUpdatable;
- private boolean mHasUpdated;
-
- private final SparseArray<DicTraverseSession> mDicTraverseSessions = new SparseArray<>();
-
- // TODO: There should be a way to remove used DicTraverseSession objects from
- // {@code mDicTraverseSessions}.
- private DicTraverseSession getTraverseSession(final int traverseSessionId) {
- synchronized(mDicTraverseSessions) {
- DicTraverseSession traverseSession = mDicTraverseSessions.get(traverseSessionId);
- if (traverseSession == null) {
- traverseSession = new DicTraverseSession(mLocale, mNativeDict, mDictSize);
- mDicTraverseSessions.put(traverseSessionId, traverseSession);
- }
- return traverseSession;
- }
- }
-
- /**
- * Constructs binary dictionary using existing dictionary file.
- * @param filename the name of the file to read through native code.
- * @param offset the offset of the dictionary data within the file.
- * @param length the length of the binary data.
- * @param useFullEditDistance whether to use the full edit distance in suggestions
- * @param dictType the dictionary type, as a human-readable string
- * @param isUpdatable whether to open the dictionary file in writable mode.
- */
- public BinaryDictionary(final String filename, final long offset, final long length,
- final boolean useFullEditDistance, final Locale locale, final String dictType,
- final boolean isUpdatable) {
- super(dictType, locale);
- mDictSize = length;
- mDictFilePath = filename;
- mIsUpdatable = isUpdatable;
- mHasUpdated = false;
- mUseFullEditDistance = useFullEditDistance;
- loadDictionary(filename, offset, length, isUpdatable);
- }
-
- /**
- * Constructs binary dictionary on memory.
- * @param filename the name of the file used to flush.
- * @param useFullEditDistance whether to use the full edit distance in suggestions
- * @param dictType the dictionary type, as a human-readable string
- * @param formatVersion the format version of the dictionary
- * @param attributeMap the attributes of the dictionary
- */
- public BinaryDictionary(final String filename, final boolean useFullEditDistance,
- final Locale locale, final String dictType, final long formatVersion,
- final Map<String, String> attributeMap) {
- super(dictType, locale);
- mDictSize = 0;
- mDictFilePath = filename;
- // On memory dictionary is always updatable.
- mIsUpdatable = true;
- mHasUpdated = false;
- mUseFullEditDistance = useFullEditDistance;
- final String[] keyArray = new String[attributeMap.size()];
- final String[] valueArray = new String[attributeMap.size()];
- int index = 0;
- for (final String key : attributeMap.keySet()) {
- keyArray[index] = key;
- valueArray[index] = attributeMap.get(key);
- index++;
- }
- mNativeDict = createOnMemoryNative(formatVersion, locale.toString(), keyArray, valueArray);
- }
-
-
- static {
- JniUtils.loadNativeLibrary();
- }
-
- private static native long openNative(String sourceDir, long dictOffset, long dictSize,
- boolean isUpdatable);
- private static native long createOnMemoryNative(long formatVersion,
- String locale, String[] attributeKeyStringArray, String[] attributeValueStringArray);
- private static native void getHeaderInfoNative(long dict, int[] outHeaderSize,
- int[] outFormatVersion, ArrayList<int[]> outAttributeKeys,
- ArrayList<int[]> outAttributeValues);
- private static native boolean flushNative(long dict, String filePath);
- private static native boolean needsToRunGCNative(long dict, boolean mindsBlockByGC);
- private static native boolean flushWithGCNative(long dict, String filePath);
- private static native void closeNative(long dict);
- private static native int getFormatVersionNative(long dict);
- private static native int getProbabilityNative(long dict, int[] word);
- private static native int getMaxProbabilityOfExactMatchesNative(long dict, int[] word);
- private static native int getNgramProbabilityNative(long dict, int[][] prevWordCodePointArrays,
- boolean[] isBeginningOfSentenceArray, int[] word);
- private static native void getWordPropertyNative(long dict, int[] word,
- boolean isBeginningOfSentence, int[] outCodePoints, boolean[] outFlags,
- int[] outProbabilityInfo, ArrayList<int[][]> outNgramPrevWordsArray,
- ArrayList<boolean[]> outNgramPrevWordIsBeginningOfSentenceArray,
- ArrayList<int[]> outNgramTargets, ArrayList<int[]> outNgramProbabilityInfo,
- ArrayList<int[]> outShortcutTargets, ArrayList<Integer> outShortcutProbabilities);
- private static native int getNextWordNative(long dict, int token, int[] outCodePoints,
- boolean[] outIsBeginningOfSentence);
- private static native void getSuggestionsNative(long dict, long proximityInfo,
- long traverseSession, int[] xCoordinates, int[] yCoordinates, int[] times,
- int[] pointerIds, int[] inputCodePoints, int inputSize, int[] suggestOptions,
- int[][] prevWordCodePointArrays, boolean[] isBeginningOfSentenceArray,
- int prevWordCount, int[] outputSuggestionCount, int[] outputCodePoints,
- int[] outputScores, int[] outputIndices, int[] outputTypes,
- int[] outputAutoCommitFirstWordConfidence,
- float[] inOutWeightOfLangModelVsSpatialModel);
- private static native boolean addUnigramEntryNative(long dict, int[] word, int probability,
- int[] shortcutTarget, int shortcutProbability, boolean isBeginningOfSentence,
- boolean isNotAWord, boolean isPossiblyOffensive, int timestamp);
- private static native boolean removeUnigramEntryNative(long dict, int[] word);
- private static native boolean addNgramEntryNative(long dict,
- int[][] prevWordCodePointArrays, boolean[] isBeginningOfSentenceArray,
- int[] word, int probability, int timestamp);
- private static native boolean removeNgramEntryNative(long dict,
- int[][] prevWordCodePointArrays, boolean[] isBeginningOfSentenceArray, int[] word);
- private static native boolean updateEntriesForWordWithNgramContextNative(long dict,
- int[][] prevWordCodePointArrays, boolean[] isBeginningOfSentenceArray,
- int[] word, boolean isValidWord, int count, int timestamp);
- private static native int updateEntriesForInputEventsNative(long dict,
- WordInputEventForPersonalization[] inputEvents, int startIndex);
- private static native String getPropertyNative(long dict, String query);
- private static native boolean isCorruptedNative(long dict);
- private static native boolean migrateNative(long dict, String dictFilePath,
- long newFormatVersion);
-
- // TODO: Move native dict into session
- private void loadDictionary(final String path, final long startOffset,
- final long length, final boolean isUpdatable) {
- mHasUpdated = false;
- mNativeDict = openNative(path, startOffset, length, isUpdatable);
- }
-
- // TODO: Check isCorrupted() for main dictionaries.
- public boolean isCorrupted() {
- if (!isValidDictionary()) {
- return false;
- }
- if (!isCorruptedNative(mNativeDict)) {
- return false;
- }
- // TODO: Record the corruption.
- Log.e(TAG, "BinaryDictionary (" + mDictFilePath + ") is corrupted.");
- Log.e(TAG, "locale: " + mLocale);
- Log.e(TAG, "dict size: " + mDictSize);
- Log.e(TAG, "updatable: " + mIsUpdatable);
- return true;
- }
-
- public DictionaryHeader getHeader() throws UnsupportedFormatException {
- if (mNativeDict == 0) {
- return null;
- }
- final int[] outHeaderSize = new int[1];
- final int[] outFormatVersion = new int[1];
- final ArrayList<int[]> outAttributeKeys = new ArrayList<>();
- final ArrayList<int[]> outAttributeValues = new ArrayList<>();
- getHeaderInfoNative(mNativeDict, outHeaderSize, outFormatVersion, outAttributeKeys,
- outAttributeValues);
- final HashMap<String, String> attributes = new HashMap<>();
- for (int i = 0; i < outAttributeKeys.size(); i++) {
- final String attributeKey = StringUtils.getStringFromNullTerminatedCodePointArray(
- outAttributeKeys.get(i));
- final String attributeValue = StringUtils.getStringFromNullTerminatedCodePointArray(
- outAttributeValues.get(i));
- attributes.put(attributeKey, attributeValue);
- }
- final boolean hasHistoricalInfo = DictionaryHeader.ATTRIBUTE_VALUE_TRUE.equals(
- attributes.get(DictionaryHeader.HAS_HISTORICAL_INFO_KEY));
- return new DictionaryHeader(outHeaderSize[0], new DictionaryOptions(attributes),
- new FormatSpec.FormatOptions(outFormatVersion[0], hasHistoricalInfo));
- }
-
- @Override
- public ArrayList<SuggestedWordInfo> getSuggestions(final ComposedData composedData,
- final NgramContext ngramContext, final long proximityInfoHandle,
- final SettingsValuesForSuggestion settingsValuesForSuggestion,
- final int sessionId, final float weightForLocale,
- final float[] inOutWeightOfLangModelVsSpatialModel) {
- if (!isValidDictionary()) {
- return null;
- }
- final DicTraverseSession session = getTraverseSession(sessionId);
- Arrays.fill(session.mInputCodePoints, Constants.NOT_A_CODE);
- ngramContext.outputToArray(session.mPrevWordCodePointArrays,
- session.mIsBeginningOfSentenceArray);
- final InputPointers inputPointers = composedData.mInputPointers;
- final boolean isGesture = composedData.mIsBatchMode;
- final int inputSize;
- if (!isGesture) {
- inputSize =
- composedData.copyCodePointsExceptTrailingSingleQuotesAndReturnCodePointCount(
- session.mInputCodePoints);
- if (inputSize < 0) {
- return null;
- }
- } else {
- inputSize = inputPointers.getPointerSize();
- }
- session.mNativeSuggestOptions.setUseFullEditDistance(mUseFullEditDistance);
- session.mNativeSuggestOptions.setIsGesture(isGesture);
- session.mNativeSuggestOptions.setBlockOffensiveWords(
- settingsValuesForSuggestion.mBlockPotentiallyOffensive);
- session.mNativeSuggestOptions.setWeightForLocale(weightForLocale);
- if (inOutWeightOfLangModelVsSpatialModel != null) {
- session.mInputOutputWeightOfLangModelVsSpatialModel[0] =
- inOutWeightOfLangModelVsSpatialModel[0];
- } else {
- session.mInputOutputWeightOfLangModelVsSpatialModel[0] =
- Dictionary.NOT_A_WEIGHT_OF_LANG_MODEL_VS_SPATIAL_MODEL;
- }
- // TOOD: Pass multiple previous words information for n-gram.
- getSuggestionsNative(mNativeDict, proximityInfoHandle,
- getTraverseSession(sessionId).getSession(), inputPointers.getXCoordinates(),
- inputPointers.getYCoordinates(), inputPointers.getTimes(),
- inputPointers.getPointerIds(), session.mInputCodePoints, inputSize,
- session.mNativeSuggestOptions.getOptions(), session.mPrevWordCodePointArrays,
- session.mIsBeginningOfSentenceArray, ngramContext.getPrevWordCount(),
- session.mOutputSuggestionCount, session.mOutputCodePoints, session.mOutputScores,
- session.mSpaceIndices, session.mOutputTypes,
- session.mOutputAutoCommitFirstWordConfidence,
- session.mInputOutputWeightOfLangModelVsSpatialModel);
- if (inOutWeightOfLangModelVsSpatialModel != null) {
- inOutWeightOfLangModelVsSpatialModel[0] =
- session.mInputOutputWeightOfLangModelVsSpatialModel[0];
- }
- final int count = session.mOutputSuggestionCount[0];
- final ArrayList<SuggestedWordInfo> suggestions = new ArrayList<>();
- for (int j = 0; j < count; ++j) {
- final int start = j * DICTIONARY_MAX_WORD_LENGTH;
- int len = 0;
- while (len < DICTIONARY_MAX_WORD_LENGTH
- && session.mOutputCodePoints[start + len] != 0) {
- ++len;
- }
- if (len > 0) {
- suggestions.add(new SuggestedWordInfo(
- new String(session.mOutputCodePoints, start, len),
- "" /* prevWordsContext */,
- (int)(session.mOutputScores[j] * weightForLocale),
- session.mOutputTypes[j],
- this /* sourceDict */,
- session.mSpaceIndices[j] /* indexOfTouchPointOfSecondWord */,
- session.mOutputAutoCommitFirstWordConfidence[0]));
- }
- }
- return suggestions;
- }
-
- public boolean isValidDictionary() {
- return mNativeDict != 0;
- }
-
- public int getFormatVersion() {
- return getFormatVersionNative(mNativeDict);
- }
-
- @Override
- public boolean isInDictionary(final String word) {
- return getFrequency(word) != NOT_A_PROBABILITY;
- }
-
- @Override
- public int getFrequency(final String word) {
- if (TextUtils.isEmpty(word)) {
- return NOT_A_PROBABILITY;
- }
- final int[] codePoints = StringUtils.toCodePointArray(word);
- return getProbabilityNative(mNativeDict, codePoints);
- }
-
- @Override
- public int getMaxFrequencyOfExactMatches(final String word) {
- if (TextUtils.isEmpty(word)) {
- return NOT_A_PROBABILITY;
- }
- final int[] codePoints = StringUtils.toCodePointArray(word);
- return getMaxProbabilityOfExactMatchesNative(mNativeDict, codePoints);
- }
-
- @UsedForTesting
- public boolean isValidNgram(final NgramContext ngramContext, final String word) {
- return getNgramProbability(ngramContext, word) != NOT_A_PROBABILITY;
- }
-
- public int getNgramProbability(final NgramContext ngramContext, final String word) {
- if (!ngramContext.isValid() || TextUtils.isEmpty(word)) {
- return NOT_A_PROBABILITY;
- }
- final int[][] prevWordCodePointArrays = new int[ngramContext.getPrevWordCount()][];
- final boolean[] isBeginningOfSentenceArray = new boolean[ngramContext.getPrevWordCount()];
- ngramContext.outputToArray(prevWordCodePointArrays, isBeginningOfSentenceArray);
- final int[] wordCodePoints = StringUtils.toCodePointArray(word);
- return getNgramProbabilityNative(mNativeDict, prevWordCodePointArrays,
- isBeginningOfSentenceArray, wordCodePoints);
- }
-
- public WordProperty getWordProperty(final String word, final boolean isBeginningOfSentence) {
- if (word == null) {
- return null;
- }
- final int[] codePoints = StringUtils.toCodePointArray(word);
- final int[] outCodePoints = new int[DICTIONARY_MAX_WORD_LENGTH];
- final boolean[] outFlags = new boolean[FORMAT_WORD_PROPERTY_OUTPUT_FLAG_COUNT];
- final int[] outProbabilityInfo =
- new int[FORMAT_WORD_PROPERTY_OUTPUT_PROBABILITY_INFO_COUNT];
- final ArrayList<int[][]> outNgramPrevWordsArray = new ArrayList<>();
- final ArrayList<boolean[]> outNgramPrevWordIsBeginningOfSentenceArray =
- new ArrayList<>();
- final ArrayList<int[]> outNgramTargets = new ArrayList<>();
- final ArrayList<int[]> outNgramProbabilityInfo = new ArrayList<>();
- final ArrayList<int[]> outShortcutTargets = new ArrayList<>();
- final ArrayList<Integer> outShortcutProbabilities = new ArrayList<>();
- getWordPropertyNative(mNativeDict, codePoints, isBeginningOfSentence, outCodePoints,
- outFlags, outProbabilityInfo, outNgramPrevWordsArray,
- outNgramPrevWordIsBeginningOfSentenceArray, outNgramTargets,
- outNgramProbabilityInfo, outShortcutTargets, outShortcutProbabilities);
- return new WordProperty(codePoints,
- outFlags[FORMAT_WORD_PROPERTY_IS_NOT_A_WORD_INDEX],
- outFlags[FORMAT_WORD_PROPERTY_IS_POSSIBLY_OFFENSIVE_INDEX],
- outFlags[FORMAT_WORD_PROPERTY_HAS_NGRAMS_INDEX],
- outFlags[FORMAT_WORD_PROPERTY_IS_BEGINNING_OF_SENTENCE_INDEX], outProbabilityInfo,
- outNgramPrevWordsArray, outNgramPrevWordIsBeginningOfSentenceArray,
- outNgramTargets, outNgramProbabilityInfo);
- }
-
- public static class GetNextWordPropertyResult {
- public WordProperty mWordProperty;
- public int mNextToken;
-
- public GetNextWordPropertyResult(final WordProperty wordProperty, final int nextToken) {
- mWordProperty = wordProperty;
- mNextToken = nextToken;
- }
- }
-
- /**
- * Method to iterate all words in the dictionary for makedict.
- * If token is 0, this method newly starts iterating the dictionary.
- */
- public GetNextWordPropertyResult getNextWordProperty(final int token) {
- final int[] codePoints = new int[DICTIONARY_MAX_WORD_LENGTH];
- final boolean[] isBeginningOfSentence = new boolean[1];
- final int nextToken = getNextWordNative(mNativeDict, token, codePoints,
- isBeginningOfSentence);
- final String word = StringUtils.getStringFromNullTerminatedCodePointArray(codePoints);
- return new GetNextWordPropertyResult(
- getWordProperty(word, isBeginningOfSentence[0]), nextToken);
- }
-
- // Add a unigram entry to binary dictionary with unigram attributes in native code.
- public boolean addUnigramEntry(
- final String word, final int probability, final boolean isBeginningOfSentence,
- final boolean isNotAWord, final boolean isPossiblyOffensive, final int timestamp) {
- if (word == null || (word.isEmpty() && !isBeginningOfSentence)) {
- return false;
- }
- final int[] codePoints = StringUtils.toCodePointArray(word);
- if (!addUnigramEntryNative(mNativeDict, codePoints, probability,
- null /* shortcutTargetCodePoints */, 0 /* shortcutProbability */,
- isBeginningOfSentence, isNotAWord, isPossiblyOffensive, timestamp)) {
- return false;
- }
- mHasUpdated = true;
- return true;
- }
-
- // Remove a unigram entry from the binary dictionary in native code.
- public boolean removeUnigramEntry(final String word) {
- if (TextUtils.isEmpty(word)) {
- return false;
- }
- final int[] codePoints = StringUtils.toCodePointArray(word);
- if (!removeUnigramEntryNative(mNativeDict, codePoints)) {
- return false;
- }
- mHasUpdated = true;
- return true;
- }
-
- // Add an n-gram entry to the binary dictionary with timestamp in native code.
- public boolean addNgramEntry(final NgramContext ngramContext, final String word,
- final int probability, final int timestamp) {
- if (!ngramContext.isValid() || TextUtils.isEmpty(word)) {
- return false;
- }
- final int[][] prevWordCodePointArrays = new int[ngramContext.getPrevWordCount()][];
- final boolean[] isBeginningOfSentenceArray = new boolean[ngramContext.getPrevWordCount()];
- ngramContext.outputToArray(prevWordCodePointArrays, isBeginningOfSentenceArray);
- final int[] wordCodePoints = StringUtils.toCodePointArray(word);
- if (!addNgramEntryNative(mNativeDict, prevWordCodePointArrays,
- isBeginningOfSentenceArray, wordCodePoints, probability, timestamp)) {
- return false;
- }
- mHasUpdated = true;
- return true;
- }
-
- // Update entries for the word occurrence with the ngramContext.
- public boolean updateEntriesForWordWithNgramContext(@Nonnull final NgramContext ngramContext,
- final String word, final boolean isValidWord, final int count, final int timestamp) {
- if (TextUtils.isEmpty(word)) {
- return false;
- }
- final int[][] prevWordCodePointArrays = new int[ngramContext.getPrevWordCount()][];
- final boolean[] isBeginningOfSentenceArray = new boolean[ngramContext.getPrevWordCount()];
- ngramContext.outputToArray(prevWordCodePointArrays, isBeginningOfSentenceArray);
- final int[] wordCodePoints = StringUtils.toCodePointArray(word);
- if (!updateEntriesForWordWithNgramContextNative(mNativeDict, prevWordCodePointArrays,
- isBeginningOfSentenceArray, wordCodePoints, isValidWord, count, timestamp)) {
- return false;
- }
- mHasUpdated = true;
- return true;
- }
-
- @UsedForTesting
- public void updateEntriesForInputEvents(final WordInputEventForPersonalization[] inputEvents) {
- if (!isValidDictionary()) {
- return;
- }
- int processedEventCount = 0;
- while (processedEventCount < inputEvents.length) {
- if (needsToRunGC(true /* mindsBlockByGC */)) {
- flushWithGC();
- }
- processedEventCount = updateEntriesForInputEventsNative(mNativeDict, inputEvents,
- processedEventCount);
- mHasUpdated = true;
- if (processedEventCount <= 0) {
- return;
- }
- }
- }
-
- private void reopen() {
- close();
- final File dictFile = new File(mDictFilePath);
- // WARNING: Because we pass 0 as the offset and file.length() as the length, this can
- // only be called for actual files. Right now it's only called by the flush() family of
- // functions, which require an updatable dictionary, so it's okay. But beware.
- loadDictionary(dictFile.getAbsolutePath(), 0 /* startOffset */,
- dictFile.length(), mIsUpdatable);
- }
-
- // Flush to dict file if the dictionary has been updated.
- public boolean flush() {
- if (!isValidDictionary()) {
- return false;
- }
- if (mHasUpdated) {
- if (!flushNative(mNativeDict, mDictFilePath)) {
- return false;
- }
- reopen();
- }
- return true;
- }
-
- // Run GC and flush to dict file if the dictionary has been updated.
- public boolean flushWithGCIfHasUpdated() {
- if (mHasUpdated) {
- return flushWithGC();
- }
- return true;
- }
-
- // Run GC and flush to dict file.
- public boolean flushWithGC() {
- if (!isValidDictionary()) {
- return false;
- }
- if (!flushWithGCNative(mNativeDict, mDictFilePath)) {
- return false;
- }
- reopen();
- return true;
- }
-
- /**
- * Checks whether GC is needed to run or not.
- * @param mindsBlockByGC Whether to mind operations blocked by GC. We don't need to care about
- * the blocking in some situations such as in idle time or just before closing.
- * @return whether GC is needed to run or not.
- */
- public boolean needsToRunGC(final boolean mindsBlockByGC) {
- if (!isValidDictionary()) {
- return false;
- }
- return needsToRunGCNative(mNativeDict, mindsBlockByGC);
- }
-
- public boolean migrateTo(final int newFormatVersion) {
- if (!isValidDictionary()) {
- return false;
- }
- final File isMigratingDir =
- new File(mDictFilePath + DIR_NAME_SUFFIX_FOR_RECORD_MIGRATION);
- if (isMigratingDir.exists()) {
- isMigratingDir.delete();
- Log.e(TAG, "Previous migration attempt failed probably due to a crash. "
- + "Giving up using the old dictionary (" + mDictFilePath + ").");
- return false;
- }
- if (!isMigratingDir.mkdir()) {
- Log.e(TAG, "Cannot create a dir (" + isMigratingDir.getAbsolutePath()
- + ") to record migration.");
- return false;
- }
- try {
- final String tmpDictFilePath = mDictFilePath + DICT_FILE_NAME_SUFFIX_FOR_MIGRATION;
- if (!migrateNative(mNativeDict, tmpDictFilePath, newFormatVersion)) {
- return false;
- }
- close();
- final File dictFile = new File(mDictFilePath);
- final File tmpDictFile = new File(tmpDictFilePath);
- if (!FileUtils.deleteRecursively(dictFile)) {
- return false;
- }
- if (!BinaryDictionaryUtils.renameDict(tmpDictFile, dictFile)) {
- return false;
- }
- loadDictionary(dictFile.getAbsolutePath(), 0 /* startOffset */,
- dictFile.length(), mIsUpdatable);
- return true;
- } finally {
- isMigratingDir.delete();
- }
- }
-
- @UsedForTesting
- public String getPropertyForGettingStats(final String query) {
- if (!isValidDictionary()) {
- return "";
- }
- return getPropertyNative(mNativeDict, query);
- }
-
- @Override
- public boolean shouldAutoCommit(final SuggestedWordInfo candidate) {
- return candidate.mAutoCommitFirstWordConfidence > CONFIDENCE_TO_AUTO_COMMIT;
- }
-
- @Override
- public void close() {
- synchronized (mDicTraverseSessions) {
- final int sessionsSize = mDicTraverseSessions.size();
- for (int index = 0; index < sessionsSize; ++index) {
- final DicTraverseSession traverseSession = mDicTraverseSessions.valueAt(index);
- if (traverseSession != null) {
- traverseSession.close();
- }
- }
- mDicTraverseSessions.clear();
- }
- closeInternalLocked();
- }
-
- private synchronized void closeInternalLocked() {
- if (mNativeDict != 0) {
- closeNative(mNativeDict);
- mNativeDict = 0;
- }
- }
-
- // TODO: Manage BinaryDictionary instances without using WeakReference or something.
- @Override
- protected void finalize() throws Throwable {
- try {
- closeInternalLocked();
- } finally {
- super.finalize();
- }
- }
-}