BinaryDictionary.java revision da0ea7603bdfb71a6134617d19535960aca4f40e
1258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani/* 2258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani * Copyright (C) 2008 The Android Open Source Project 3258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani * 4258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani * Licensed under the Apache License, Version 2.0 (the "License"); 5258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani * you may not use this file except in compliance with the License. 6258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani * You may obtain a copy of the License at 7258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani * 8258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani * http://www.apache.org/licenses/LICENSE-2.0 9258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani * 10258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani * Unless required by applicable law or agreed to in writing, software 11258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani * distributed under the License is distributed on an "AS IS" BASIS, 12258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani * See the License for the specific language governing permissions and 14258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani * limitations under the License. 15258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani */ 16258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani 17258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasanipackage com.android.inputmethod.latin; 180e8d7d63ba439cc0604af7055679dae3d30fdc48Amith Yamasani 19409297da182267465adbc21cfb75a23e8d678117Dianne Hackbornimport android.text.TextUtils; 20a8a9bd65bf5865d83ef44f54552ca39522bfbcf0Dianne Hackbornimport android.util.Log; 21258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasaniimport android.util.SparseArray; 22258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani 2327bd34d9d9fe99f11b80aa0bbdb402fb47ef4158Jeff Sharkeyimport com.android.inputmethod.annotations.UsedForTesting; 246794458f8626c3be27eac3db3a5c89d94f132675Maggie Benthallimport com.android.inputmethod.keyboard.ProximityInfo; 251bdff9139fd412b36d5d2d783574b6418fcb198aAdrian Roosimport com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; 264f58263d02f296430a9653126d28501e95c7bb6cAmith Yamasaniimport com.android.inputmethod.latin.makedict.DictionaryHeader; 274f58263d02f296430a9653126d28501e95c7bb6cAmith Yamasaniimport com.android.inputmethod.latin.makedict.FormatSpec; 281e9c21871e81642669079cd290ef47818a3165bdAmith Yamasaniimport com.android.inputmethod.latin.makedict.FormatSpec.DictionaryOptions; 29258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasaniimport com.android.inputmethod.latin.makedict.UnsupportedFormatException; 301c7c319bb89b9988bfd12afc3e8d89449fd163fcJason Monkimport com.android.inputmethod.latin.makedict.WordProperty; 31258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasaniimport com.android.inputmethod.latin.settings.NativeSuggestOptions; 326794458f8626c3be27eac3db3a5c89d94f132675Maggie Benthallimport com.android.inputmethod.latin.utils.BinaryDictionaryUtils; 336794458f8626c3be27eac3db3a5c89d94f132675Maggie Benthallimport com.android.inputmethod.latin.utils.FileUtils; 341bdff9139fd412b36d5d2d783574b6418fcb198aAdrian Roosimport com.android.inputmethod.latin.utils.JniUtils; 354f58263d02f296430a9653126d28501e95c7bb6cAmith Yamasaniimport com.android.inputmethod.latin.utils.LanguageModelParam; 36258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasaniimport com.android.inputmethod.latin.utils.StringUtils; 37258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani 38258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasaniimport java.io.File; 39258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasaniimport java.util.ArrayList; 40258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasaniimport java.util.Arrays; 41258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasaniimport java.util.HashMap; 42258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasaniimport java.util.Locale; 43258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasaniimport java.util.Map; 44258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani 45258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani/** 46258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani * Implements a static, compacted, binary dictionary of standard words. 47e4cf73437a18c1444055f88a1fcc0d146ec23ac5Amith Yamasani */ 4826af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani// TODO: All methods which should be locked need to have a suffix "Locked". 4971e6c697e54a43d357cc25d87a446d140f17396aAmith Yamasanipublic final class BinaryDictionary extends Dictionary { 5026af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani private static final String TAG = BinaryDictionary.class.getSimpleName(); 5126af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani 5226af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani // Must be equal to MAX_WORD_LENGTH in native/jni/src/defines.h 53e4cf73437a18c1444055f88a1fcc0d146ec23ac5Amith Yamasani private static final int MAX_WORD_LENGTH = Constants.DICTIONARY_MAX_WORD_LENGTH; 54e4cf73437a18c1444055f88a1fcc0d146ec23ac5Amith Yamasani // Must be equal to MAX_RESULTS in native/jni/src/defines.h 55e4cf73437a18c1444055f88a1fcc0d146ec23ac5Amith Yamasani private static final int MAX_RESULTS = 18; 5671e6c697e54a43d357cc25d87a446d140f17396aAmith Yamasani // The cutoff returned by native for auto-commit confidence. 57e4cf73437a18c1444055f88a1fcc0d146ec23ac5Amith Yamasani // Must be equal to CONFIDENCE_TO_AUTO_COMMIT in native/jni/src/defines.h 58e4cf73437a18c1444055f88a1fcc0d146ec23ac5Amith Yamasani private static final int CONFIDENCE_TO_AUTO_COMMIT = 1000000; 5926af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani 602cb384f42569f36e19ecee60da259d69048fdd85Julia Reynolds @UsedForTesting 61150514bd03312ab0a890cc040019cfbc73eb077cAmith Yamasani public static final String UNIGRAM_COUNT_QUERY = "UNIGRAM_COUNT"; 6226af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani @UsedForTesting 6326af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani public static final String BIGRAM_COUNT_QUERY = "BIGRAM_COUNT"; 6426af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani @UsedForTesting 65e4cf73437a18c1444055f88a1fcc0d146ec23ac5Amith Yamasani public static final String MAX_UNIGRAM_COUNT_QUERY = "MAX_UNIGRAM_COUNT"; 66e4cf73437a18c1444055f88a1fcc0d146ec23ac5Amith Yamasani @UsedForTesting 67e4cf73437a18c1444055f88a1fcc0d146ec23ac5Amith Yamasani public static final String MAX_BIGRAM_COUNT_QUERY = "MAX_BIGRAM_COUNT"; 6871e6c697e54a43d357cc25d87a446d140f17396aAmith Yamasani 69e4cf73437a18c1444055f88a1fcc0d146ec23ac5Amith Yamasani public static final int NOT_A_VALID_TIMESTAMP = -1; 70e4cf73437a18c1444055f88a1fcc0d146ec23ac5Amith Yamasani 7126af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani // Format to get unigram flags from native side via getWordPropertyNative(). 7271e6c697e54a43d357cc25d87a446d140f17396aAmith Yamasani private static final int FORMAT_WORD_PROPERTY_OUTPUT_FLAG_COUNT = 4; 7326af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani private static final int FORMAT_WORD_PROPERTY_IS_NOT_A_WORD_INDEX = 0; 7426af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani private static final int FORMAT_WORD_PROPERTY_IS_BLACKLISTED_INDEX = 1; 7526af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani private static final int FORMAT_WORD_PROPERTY_HAS_BIGRAMS_INDEX = 2; 76e4cf73437a18c1444055f88a1fcc0d146ec23ac5Amith Yamasani private static final int FORMAT_WORD_PROPERTY_HAS_SHORTCUTS_INDEX = 3; 77e4cf73437a18c1444055f88a1fcc0d146ec23ac5Amith Yamasani 78e4cf73437a18c1444055f88a1fcc0d146ec23ac5Amith Yamasani // Format to get probability and historical info from native side via getWordPropertyNative(). 7971e6c697e54a43d357cc25d87a446d140f17396aAmith Yamasani public static final int FORMAT_WORD_PROPERTY_OUTPUT_PROBABILITY_INFO_COUNT = 4; 80e4cf73437a18c1444055f88a1fcc0d146ec23ac5Amith Yamasani public static final int FORMAT_WORD_PROPERTY_PROBABILITY_INDEX = 0; 81e4cf73437a18c1444055f88a1fcc0d146ec23ac5Amith Yamasani public static final int FORMAT_WORD_PROPERTY_TIMESTAMP_INDEX = 1; 8226af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani public static final int FORMAT_WORD_PROPERTY_LEVEL_INDEX = 2; 8371e6c697e54a43d357cc25d87a446d140f17396aAmith Yamasani public static final int FORMAT_WORD_PROPERTY_COUNT_INDEX = 3; 8426af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani 8526af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani public static final String DICT_FILE_NAME_SUFFIX_FOR_MIGRATION = ".migrate"; 8626af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani 87e4cf73437a18c1444055f88a1fcc0d146ec23ac5Amith Yamasani private long mNativeDict; 88e4cf73437a18c1444055f88a1fcc0d146ec23ac5Amith Yamasani private final Locale mLocale; 89e4cf73437a18c1444055f88a1fcc0d146ec23ac5Amith Yamasani private final long mDictSize; 9071e6c697e54a43d357cc25d87a446d140f17396aAmith Yamasani private final String mDictFilePath; 91e4cf73437a18c1444055f88a1fcc0d146ec23ac5Amith Yamasani private final boolean mIsUpdatable; 9271e6c697e54a43d357cc25d87a446d140f17396aAmith Yamasani private boolean mHasUpdated; 93150514bd03312ab0a890cc040019cfbc73eb077cAmith Yamasani 9471e6c697e54a43d357cc25d87a446d140f17396aAmith Yamasani private final int[] mInputCodePoints = new int[MAX_WORD_LENGTH]; 95150514bd03312ab0a890cc040019cfbc73eb077cAmith Yamasani private final int[] mOutputSuggestionCount = new int[1]; 96150514bd03312ab0a890cc040019cfbc73eb077cAmith Yamasani private final int[] mOutputCodePoints = new int[MAX_WORD_LENGTH * MAX_RESULTS]; 9726af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani private final int[] mSpaceIndices = new int[MAX_RESULTS]; 9826af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani private final int[] mOutputScores = new int[MAX_RESULTS]; 9926af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani private final int[] mOutputTypes = new int[MAX_RESULTS]; 1006794458f8626c3be27eac3db3a5c89d94f132675Maggie Benthall // Only one result is ever used 1016794458f8626c3be27eac3db3a5c89d94f132675Maggie Benthall private final int[] mOutputAutoCommitFirstWordConfidence = new int[1]; 1026794458f8626c3be27eac3db3a5c89d94f132675Maggie Benthall private final float[] mInputOutputLanguageWeight = new float[1]; 10371e6c697e54a43d357cc25d87a446d140f17396aAmith Yamasani 1046794458f8626c3be27eac3db3a5c89d94f132675Maggie Benthall private final NativeSuggestOptions mNativeSuggestOptions = new NativeSuggestOptions(); 105a12fccf57d5ec289793699d9b22ff45daccd3933Maggie Benthall 10626af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani private final SparseArray<DicTraverseSession> mDicTraverseSessions = new SparseArray<>(); 107a12fccf57d5ec289793699d9b22ff45daccd3933Maggie Benthall 108a12fccf57d5ec289793699d9b22ff45daccd3933Maggie Benthall // TODO: There should be a way to remove used DicTraverseSession objects from 10926af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani // {@code mDicTraverseSessions}. 11026af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani private DicTraverseSession getTraverseSession(final int traverseSessionId) { 11126af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani synchronized(mDicTraverseSessions) { 112a12fccf57d5ec289793699d9b22ff45daccd3933Maggie Benthall DicTraverseSession traverseSession = mDicTraverseSessions.get(traverseSessionId); 113a12fccf57d5ec289793699d9b22ff45daccd3933Maggie Benthall if (traverseSession == null) { 114a12fccf57d5ec289793699d9b22ff45daccd3933Maggie Benthall traverseSession = new DicTraverseSession(mLocale, mNativeDict, mDictSize); 115a12fccf57d5ec289793699d9b22ff45daccd3933Maggie Benthall mDicTraverseSessions.put(traverseSessionId, traverseSession); 116a12fccf57d5ec289793699d9b22ff45daccd3933Maggie Benthall } 117a12fccf57d5ec289793699d9b22ff45daccd3933Maggie Benthall return traverseSession; 11826af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani } 1191c4c442e4540b16aed7acc345aea26ab101efbf8Nicolas Prevot } 120a12fccf57d5ec289793699d9b22ff45daccd3933Maggie Benthall 121150514bd03312ab0a890cc040019cfbc73eb077cAmith Yamasani /** 12226af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani * Constructs binary dictionary using existing dictionary file. 12326af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani * @param filename the name of the file to read through native code. 12426af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani * @param offset the offset of the dictionary data within the file. 125a12fccf57d5ec289793699d9b22ff45daccd3933Maggie Benthall * @param length the length of the binary data. 126a12fccf57d5ec289793699d9b22ff45daccd3933Maggie Benthall * @param useFullEditDistance whether to use the full edit distance in suggestions 127a12fccf57d5ec289793699d9b22ff45daccd3933Maggie Benthall * @param dictType the dictionary type, as a human-readable string 128a12fccf57d5ec289793699d9b22ff45daccd3933Maggie Benthall * @param isUpdatable whether to open the dictionary file in writable mode. 129a12fccf57d5ec289793699d9b22ff45daccd3933Maggie Benthall */ 130a12fccf57d5ec289793699d9b22ff45daccd3933Maggie Benthall public BinaryDictionary(final String filename, final long offset, final long length, 13126af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani final boolean useFullEditDistance, final Locale locale, final String dictType, 132c34dc7cdeb5cae8ca4c731838aafe90ed4c9a2b8Amith Yamasani final boolean isUpdatable) { 133c34dc7cdeb5cae8ca4c731838aafe90ed4c9a2b8Amith Yamasani super(dictType); 13426af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani mLocale = locale; 13526af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani mDictSize = length; 13626af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani mDictFilePath = filename; 137a12fccf57d5ec289793699d9b22ff45daccd3933Maggie Benthall mIsUpdatable = isUpdatable; 138a12fccf57d5ec289793699d9b22ff45daccd3933Maggie Benthall mHasUpdated = false; 139a12fccf57d5ec289793699d9b22ff45daccd3933Maggie Benthall mNativeSuggestOptions.setUseFullEditDistance(useFullEditDistance); 140a12fccf57d5ec289793699d9b22ff45daccd3933Maggie Benthall loadDictionary(filename, offset, length, isUpdatable); 141a12fccf57d5ec289793699d9b22ff45daccd3933Maggie Benthall } 142b223f73a69f76f5e32a0bca267f945f464776f9dEmily Bernier 14326af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani /** 144b223f73a69f76f5e32a0bca267f945f464776f9dEmily Bernier * Constructs binary dictionary on memory. 14526af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani * @param filename the name of the file used to flush. 14626af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani * @param useFullEditDistance whether to use the full edit distance in suggestions 14726af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani * @param dictType the dictionary type, as a human-readable string 148b223f73a69f76f5e32a0bca267f945f464776f9dEmily Bernier * @param formatVersion the format version of the dictionary 149b223f73a69f76f5e32a0bca267f945f464776f9dEmily Bernier * @param attributeMap the attributes of the dictionary 150b223f73a69f76f5e32a0bca267f945f464776f9dEmily Bernier */ 151b223f73a69f76f5e32a0bca267f945f464776f9dEmily Bernier @UsedForTesting 152b223f73a69f76f5e32a0bca267f945f464776f9dEmily Bernier public BinaryDictionary(final String filename, final boolean useFullEditDistance, 153b223f73a69f76f5e32a0bca267f945f464776f9dEmily Bernier final Locale locale, final String dictType, final long formatVersion, 154150514bd03312ab0a890cc040019cfbc73eb077cAmith Yamasani final Map<String, String> attributeMap) { 155150514bd03312ab0a890cc040019cfbc73eb077cAmith Yamasani super(dictType); 156150514bd03312ab0a890cc040019cfbc73eb077cAmith Yamasani mLocale = locale; 157150514bd03312ab0a890cc040019cfbc73eb077cAmith Yamasani mDictSize = 0; 15826af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani mDictFilePath = filename; 15926af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani // On memory dictionary is always updatable. 16026af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani mIsUpdatable = true; 161b223f73a69f76f5e32a0bca267f945f464776f9dEmily Bernier mHasUpdated = false; 162b223f73a69f76f5e32a0bca267f945f464776f9dEmily Bernier mNativeSuggestOptions.setUseFullEditDistance(useFullEditDistance); 163b223f73a69f76f5e32a0bca267f945f464776f9dEmily Bernier final String[] keyArray = new String[attributeMap.size()]; 164b223f73a69f76f5e32a0bca267f945f464776f9dEmily Bernier final String[] valueArray = new String[attributeMap.size()]; 165b223f73a69f76f5e32a0bca267f945f464776f9dEmily Bernier int index = 0; 166d46d0f9dcd72dfaa93a57d07d896def6ce53bbaeJulia Reynolds for (final String key : attributeMap.keySet()) { 16726af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani keyArray[index] = key; 168d46d0f9dcd72dfaa93a57d07d896def6ce53bbaeJulia Reynolds valueArray[index] = attributeMap.get(key); 16926af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani index++; 17026af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani } 17126af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani mNativeDict = createOnMemoryNative(formatVersion, locale.toString(), keyArray, valueArray); 172d46d0f9dcd72dfaa93a57d07d896def6ce53bbaeJulia Reynolds } 173d46d0f9dcd72dfaa93a57d07d896def6ce53bbaeJulia Reynolds 174d46d0f9dcd72dfaa93a57d07d896def6ce53bbaeJulia Reynolds 175d46d0f9dcd72dfaa93a57d07d896def6ce53bbaeJulia Reynolds static { 176d46d0f9dcd72dfaa93a57d07d896def6ce53bbaeJulia Reynolds JniUtils.loadNativeLibrary(); 177d46d0f9dcd72dfaa93a57d07d896def6ce53bbaeJulia Reynolds } 17826af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani 179d46d0f9dcd72dfaa93a57d07d896def6ce53bbaeJulia Reynolds private static native long openNative(String sourceDir, long dictOffset, long dictSize, 180298f98fa234f353267ddc9c75d58e8cc542c25f1Nicolas Prevot boolean isUpdatable); 181298f98fa234f353267ddc9c75d58e8cc542c25f1Nicolas Prevot private static native long createOnMemoryNative(long formatVersion, 18226af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani String locale, String[] attributeKeyStringArray, String[] attributeValueStringArray); 18326af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani private static native void getHeaderInfoNative(long dict, int[] outHeaderSize, 18426af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani int[] outFormatVersion, ArrayList<int[]> outAttributeKeys, 185d46d0f9dcd72dfaa93a57d07d896def6ce53bbaeJulia Reynolds ArrayList<int[]> outAttributeValues); 186d46d0f9dcd72dfaa93a57d07d896def6ce53bbaeJulia Reynolds private static native boolean flushNative(long dict, String filePath); 187d46d0f9dcd72dfaa93a57d07d896def6ce53bbaeJulia Reynolds private static native boolean needsToRunGCNative(long dict, boolean mindsBlockByGC); 188d46d0f9dcd72dfaa93a57d07d896def6ce53bbaeJulia Reynolds private static native boolean flushWithGCNative(long dict, String filePath); 189d46d0f9dcd72dfaa93a57d07d896def6ce53bbaeJulia Reynolds private static native void closeNative(long dict); 190d46d0f9dcd72dfaa93a57d07d896def6ce53bbaeJulia Reynolds private static native int getFormatVersionNative(long dict); 19126af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani private static native int getProbabilityNative(long dict, int[] word); 192c34dc7cdeb5cae8ca4c731838aafe90ed4c9a2b8Amith Yamasani private static native int getMaxProbabilityOfExactMatchesNative(long dict, int[] word); 193c34dc7cdeb5cae8ca4c731838aafe90ed4c9a2b8Amith Yamasani private static native int getBigramProbabilityNative(long dict, int[] word0, 19426af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani boolean isBeginningOfSentence, int[] word1); 19526af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani private static native void getWordPropertyNative(long dict, int[] word, 19626af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani int[] outCodePoints, boolean[] outFlags, int[] outProbabilityInfo, 197d46d0f9dcd72dfaa93a57d07d896def6ce53bbaeJulia Reynolds ArrayList<int[]> outBigramTargets, ArrayList<int[]> outBigramProbabilityInfo, 198d46d0f9dcd72dfaa93a57d07d896def6ce53bbaeJulia Reynolds ArrayList<int[]> outShortcutTargets, ArrayList<Integer> outShortcutProbabilities); 199d46d0f9dcd72dfaa93a57d07d896def6ce53bbaeJulia Reynolds private static native int getNextWordNative(long dict, int token, int[] outCodePoints); 200d46d0f9dcd72dfaa93a57d07d896def6ce53bbaeJulia Reynolds private static native void getSuggestionsNative(long dict, long proximityInfo, 201d46d0f9dcd72dfaa93a57d07d896def6ce53bbaeJulia Reynolds long traverseSession, int[] xCoordinates, int[] yCoordinates, int[] times, 202d46d0f9dcd72dfaa93a57d07d896def6ce53bbaeJulia Reynolds int[] pointerIds, int[] inputCodePoints, int inputSize, int[] suggestOptions, 203e3e314df4d52881225326d426a76e3e7f1bc40d3Stuart Scott int[] prevWordCodePointArray, boolean isBeginningOfSentence, 204e3e314df4d52881225326d426a76e3e7f1bc40d3Stuart Scott int[] outputSuggestionCount, int[] outputCodePoints, int[] outputScores, 205e3e314df4d52881225326d426a76e3e7f1bc40d3Stuart Scott int[] outputIndices, int[] outputTypes, int[] outputAutoCommitFirstWordConfidence, 206e3e314df4d52881225326d426a76e3e7f1bc40d3Stuart Scott float[] inOutLanguageWeight); 207e3e314df4d52881225326d426a76e3e7f1bc40d3Stuart Scott private static native boolean addUnigramWordNative(long dict, int[] word, int probability, 208e3e314df4d52881225326d426a76e3e7f1bc40d3Stuart Scott int[] shortcutTarget, int shortcutProbability, boolean isBeginningOfSentence, 209e3e314df4d52881225326d426a76e3e7f1bc40d3Stuart Scott boolean isNotAWord, boolean isBlacklisted, int timestamp); 210e3e314df4d52881225326d426a76e3e7f1bc40d3Stuart Scott private static native boolean removeUnigramWordNative(long dict, int[] word); 211e3e314df4d52881225326d426a76e3e7f1bc40d3Stuart Scott private static native boolean addBigramWordsNative(long dict, int[] word0, 212e3e314df4d52881225326d426a76e3e7f1bc40d3Stuart Scott boolean isBeginningOfSentence, int[] word1, int probability, int timestamp); 213e3e314df4d52881225326d426a76e3e7f1bc40d3Stuart Scott private static native boolean removeBigramWordsNative(long dict, int[] word0, 214e3e314df4d52881225326d426a76e3e7f1bc40d3Stuart Scott boolean isBeginningOfSentence, int[] word1); 215e3e314df4d52881225326d426a76e3e7f1bc40d3Stuart Scott private static native int addMultipleDictionaryEntriesNative(long dict, 216e3e314df4d52881225326d426a76e3e7f1bc40d3Stuart Scott LanguageModelParam[] languageModelParams, int startIndex); 21726af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani private static native String getPropertyNative(long dict, String query); 218c34dc7cdeb5cae8ca4c731838aafe90ed4c9a2b8Amith Yamasani private static native boolean isCorruptedNative(long dict); 219c34dc7cdeb5cae8ca4c731838aafe90ed4c9a2b8Amith Yamasani private static native boolean migrateNative(long dict, String dictFilePath, 220150514bd03312ab0a890cc040019cfbc73eb077cAmith Yamasani long newFormatVersion); 221150514bd03312ab0a890cc040019cfbc73eb077cAmith Yamasani 22226af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani // TODO: Move native dict into session 22326af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani private final void loadDictionary(final String path, final long startOffset, 22426af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani final long length, final boolean isUpdatable) { 225d46d0f9dcd72dfaa93a57d07d896def6ce53bbaeJulia Reynolds mHasUpdated = false; 226d46d0f9dcd72dfaa93a57d07d896def6ce53bbaeJulia Reynolds mNativeDict = openNative(path, startOffset, length, isUpdatable); 227d46d0f9dcd72dfaa93a57d07d896def6ce53bbaeJulia Reynolds } 228d46d0f9dcd72dfaa93a57d07d896def6ce53bbaeJulia Reynolds 229d46d0f9dcd72dfaa93a57d07d896def6ce53bbaeJulia Reynolds // TODO: Check isCorrupted() for main dictionaries. 230d46d0f9dcd72dfaa93a57d07d896def6ce53bbaeJulia Reynolds public boolean isCorrupted() { 23126af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani if (!isValidDictionary()) { 232c34dc7cdeb5cae8ca4c731838aafe90ed4c9a2b8Amith Yamasani return false; 233c34dc7cdeb5cae8ca4c731838aafe90ed4c9a2b8Amith Yamasani } 234150514bd03312ab0a890cc040019cfbc73eb077cAmith Yamasani if (!isCorruptedNative(mNativeDict)) { 235150514bd03312ab0a890cc040019cfbc73eb077cAmith Yamasani return false; 23626af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani } 23726af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani // TODO: Record the corruption. 23826af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani Log.e(TAG, "BinaryDictionary (" + mDictFilePath + ") is corrupted."); 239d46d0f9dcd72dfaa93a57d07d896def6ce53bbaeJulia Reynolds Log.e(TAG, "locale: " + mLocale); 240d46d0f9dcd72dfaa93a57d07d896def6ce53bbaeJulia Reynolds Log.e(TAG, "dict size: " + mDictSize); 241d46d0f9dcd72dfaa93a57d07d896def6ce53bbaeJulia Reynolds Log.e(TAG, "updatable: " + mIsUpdatable); 242d46d0f9dcd72dfaa93a57d07d896def6ce53bbaeJulia Reynolds return true; 243d46d0f9dcd72dfaa93a57d07d896def6ce53bbaeJulia Reynolds } 244d46d0f9dcd72dfaa93a57d07d896def6ce53bbaeJulia Reynolds 24526af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani public DictionaryHeader getHeader() throws UnsupportedFormatException { 246d46d0f9dcd72dfaa93a57d07d896def6ce53bbaeJulia Reynolds if (mNativeDict == 0) { 24726af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani return null; 24826af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani } 24926af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani final int[] outHeaderSize = new int[1]; 250d46d0f9dcd72dfaa93a57d07d896def6ce53bbaeJulia Reynolds final int[] outFormatVersion = new int[1]; 251d46d0f9dcd72dfaa93a57d07d896def6ce53bbaeJulia Reynolds final ArrayList<int[]> outAttributeKeys = new ArrayList<>(); 252d46d0f9dcd72dfaa93a57d07d896def6ce53bbaeJulia Reynolds final ArrayList<int[]> outAttributeValues = new ArrayList<>(); 253d46d0f9dcd72dfaa93a57d07d896def6ce53bbaeJulia Reynolds getHeaderInfoNative(mNativeDict, outHeaderSize, outFormatVersion, outAttributeKeys, 254d46d0f9dcd72dfaa93a57d07d896def6ce53bbaeJulia Reynolds outAttributeValues); 255d46d0f9dcd72dfaa93a57d07d896def6ce53bbaeJulia Reynolds final HashMap<String, String> attributes = new HashMap<>(); 25626af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani for (int i = 0; i < outAttributeKeys.size(); i++) { 257c34dc7cdeb5cae8ca4c731838aafe90ed4c9a2b8Amith Yamasani final String attributeKey = StringUtils.getStringFromNullTerminatedCodePointArray( 258c34dc7cdeb5cae8ca4c731838aafe90ed4c9a2b8Amith Yamasani outAttributeKeys.get(i)); 259150514bd03312ab0a890cc040019cfbc73eb077cAmith Yamasani final String attributeValue = StringUtils.getStringFromNullTerminatedCodePointArray( 260150514bd03312ab0a890cc040019cfbc73eb077cAmith Yamasani outAttributeValues.get(i)); 26126af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani attributes.put(attributeKey, attributeValue); 26226af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani } 26326af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani final boolean hasHistoricalInfo = DictionaryHeader.ATTRIBUTE_VALUE_TRUE.equals( 264d46d0f9dcd72dfaa93a57d07d896def6ce53bbaeJulia Reynolds attributes.get(DictionaryHeader.HAS_HISTORICAL_INFO_KEY)); 265d46d0f9dcd72dfaa93a57d07d896def6ce53bbaeJulia Reynolds return new DictionaryHeader(outHeaderSize[0], new DictionaryOptions(attributes), 266d46d0f9dcd72dfaa93a57d07d896def6ce53bbaeJulia Reynolds new FormatSpec.FormatOptions(outFormatVersion[0], hasHistoricalInfo)); 267d46d0f9dcd72dfaa93a57d07d896def6ce53bbaeJulia Reynolds } 268d46d0f9dcd72dfaa93a57d07d896def6ce53bbaeJulia Reynolds 269d46d0f9dcd72dfaa93a57d07d896def6ce53bbaeJulia Reynolds @Override 27026af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani public ArrayList<SuggestedWordInfo> getSuggestions(final WordComposer composer, 271c34dc7cdeb5cae8ca4c731838aafe90ed4c9a2b8Amith Yamasani final PrevWordsInfo prevWordsInfo, final ProximityInfo proximityInfo, 272c34dc7cdeb5cae8ca4c731838aafe90ed4c9a2b8Amith Yamasani final boolean blockOffensiveWords, final int[] additionalFeaturesOptions, 273150514bd03312ab0a890cc040019cfbc73eb077cAmith Yamasani final int sessionId, final float[] inOutLanguageWeight) { 274150514bd03312ab0a890cc040019cfbc73eb077cAmith Yamasani if (!isValidDictionary()) { 27526af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani return null; 27626af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani } 27726af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani 278d46d0f9dcd72dfaa93a57d07d896def6ce53bbaeJulia Reynolds Arrays.fill(mInputCodePoints, Constants.NOT_A_CODE); 279d46d0f9dcd72dfaa93a57d07d896def6ce53bbaeJulia Reynolds // TODO: toLowerCase in the native code 280d46d0f9dcd72dfaa93a57d07d896def6ce53bbaeJulia Reynolds final int[] prevWordCodePointArray = (null == prevWordsInfo.mPrevWord) 281d46d0f9dcd72dfaa93a57d07d896def6ce53bbaeJulia Reynolds ? null : StringUtils.toCodePointArray(prevWordsInfo.mPrevWord); 282d46d0f9dcd72dfaa93a57d07d896def6ce53bbaeJulia Reynolds final InputPointers inputPointers = composer.getInputPointers(); 283d46d0f9dcd72dfaa93a57d07d896def6ce53bbaeJulia Reynolds final boolean isGesture = composer.isBatchMode(); 28426af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani final int inputSize; 285c617f815453b6e70a0165924907e69a0f993e651Julia Reynolds if (!isGesture) { 286c617f815453b6e70a0165924907e69a0f993e651Julia Reynolds inputSize = composer.copyCodePointsExceptTrailingSingleQuotesAndReturnCodePointCount( 287c617f815453b6e70a0165924907e69a0f993e651Julia Reynolds mInputCodePoints); 288c617f815453b6e70a0165924907e69a0f993e651Julia Reynolds if (inputSize < 0) { 289c617f815453b6e70a0165924907e69a0f993e651Julia Reynolds return null; 290c617f815453b6e70a0165924907e69a0f993e651Julia Reynolds } 291c617f815453b6e70a0165924907e69a0f993e651Julia Reynolds } else { 292c617f815453b6e70a0165924907e69a0f993e651Julia Reynolds inputSize = inputPointers.getPointerSize(); 293c617f815453b6e70a0165924907e69a0f993e651Julia Reynolds } 294c617f815453b6e70a0165924907e69a0f993e651Julia Reynolds 29526af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani mNativeSuggestOptions.setIsGesture(isGesture); 29626af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani mNativeSuggestOptions.setBlockOffensiveWords(blockOffensiveWords); 29726af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani mNativeSuggestOptions.setAdditionalFeaturesOptions(additionalFeaturesOptions); 298d46d0f9dcd72dfaa93a57d07d896def6ce53bbaeJulia Reynolds if (inOutLanguageWeight != null) { 299d46d0f9dcd72dfaa93a57d07d896def6ce53bbaeJulia Reynolds mInputOutputLanguageWeight[0] = inOutLanguageWeight[0]; 300d46d0f9dcd72dfaa93a57d07d896def6ce53bbaeJulia Reynolds } else { 30136fbc8d6453da438a8ab83352ff1bcfcba5f25b5Julia Reynolds mInputOutputLanguageWeight[0] = Dictionary.NOT_A_LANGUAGE_WEIGHT; 302d46d0f9dcd72dfaa93a57d07d896def6ce53bbaeJulia Reynolds } 303394a6cdd987fed79bd040f39e2d3e47d4484bab4Emily Bernier // proximityInfo and/or prevWordForBigrams may not be null. 30426af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani getSuggestionsNative(mNativeDict, proximityInfo.getNativeProximityInfo(), 305c34dc7cdeb5cae8ca4c731838aafe90ed4c9a2b8Amith Yamasani getTraverseSession(sessionId).getSession(), inputPointers.getXCoordinates(), 306c34dc7cdeb5cae8ca4c731838aafe90ed4c9a2b8Amith Yamasani inputPointers.getYCoordinates(), inputPointers.getTimes(), 30726af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani inputPointers.getPointerIds(), mInputCodePoints, inputSize, 30826af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani mNativeSuggestOptions.getOptions(), prevWordCodePointArray, 30926af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani prevWordsInfo.mIsBeginningOfSentence, mOutputSuggestionCount, 310394a6cdd987fed79bd040f39e2d3e47d4484bab4Emily Bernier mOutputCodePoints, mOutputScores, mSpaceIndices, mOutputTypes, 311394a6cdd987fed79bd040f39e2d3e47d4484bab4Emily Bernier mOutputAutoCommitFirstWordConfidence, mInputOutputLanguageWeight); 312394a6cdd987fed79bd040f39e2d3e47d4484bab4Emily Bernier if (inOutLanguageWeight != null) { 313394a6cdd987fed79bd040f39e2d3e47d4484bab4Emily Bernier inOutLanguageWeight[0] = mInputOutputLanguageWeight[0]; 314394a6cdd987fed79bd040f39e2d3e47d4484bab4Emily Bernier } 315394a6cdd987fed79bd040f39e2d3e47d4484bab4Emily Bernier final int count = mOutputSuggestionCount[0]; 31626af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani final ArrayList<SuggestedWordInfo> suggestions = new ArrayList<>(); 317c34dc7cdeb5cae8ca4c731838aafe90ed4c9a2b8Amith Yamasani for (int j = 0; j < count; ++j) { 318c34dc7cdeb5cae8ca4c731838aafe90ed4c9a2b8Amith Yamasani final int start = j * MAX_WORD_LENGTH; 31926af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani int len = 0; 32026af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani while (len < MAX_WORD_LENGTH && mOutputCodePoints[start + len] != 0) { 32126af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani ++len; 322394a6cdd987fed79bd040f39e2d3e47d4484bab4Emily Bernier } 323394a6cdd987fed79bd040f39e2d3e47d4484bab4Emily Bernier if (len > 0) { 324394a6cdd987fed79bd040f39e2d3e47d4484bab4Emily Bernier suggestions.add(new SuggestedWordInfo(new String(mOutputCodePoints, start, len), 325394a6cdd987fed79bd040f39e2d3e47d4484bab4Emily Bernier mOutputScores[j], mOutputTypes[j], this /* sourceDict */, 326394a6cdd987fed79bd040f39e2d3e47d4484bab4Emily Bernier mSpaceIndices[j] /* indexOfTouchPointOfSecondWord */, 327394a6cdd987fed79bd040f39e2d3e47d4484bab4Emily Bernier mOutputAutoCommitFirstWordConfidence[0])); 32826af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani } 329c34dc7cdeb5cae8ca4c731838aafe90ed4c9a2b8Amith Yamasani } 330c34dc7cdeb5cae8ca4c731838aafe90ed4c9a2b8Amith Yamasani return suggestions; 33126af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani } 33226af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani 33326af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani public boolean isValidDictionary() { 334394a6cdd987fed79bd040f39e2d3e47d4484bab4Emily Bernier return mNativeDict != 0; 335394a6cdd987fed79bd040f39e2d3e47d4484bab4Emily Bernier } 336394a6cdd987fed79bd040f39e2d3e47d4484bab4Emily Bernier 337394a6cdd987fed79bd040f39e2d3e47d4484bab4Emily Bernier public int getFormatVersion() { 338394a6cdd987fed79bd040f39e2d3e47d4484bab4Emily Bernier return getFormatVersionNative(mNativeDict); 3399f6c25f57e26f3e2f9c744547a139d14b7d3db5cAmith Yamasani } 34026af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani 341390989da1967f9d385212cd2e22a50589ce69046Amith Yamasani @Override 342390989da1967f9d385212cd2e22a50589ce69046Amith Yamasani public boolean isInDictionary(final String word) { 343150514bd03312ab0a890cc040019cfbc73eb077cAmith Yamasani return getFrequency(word) != NOT_A_PROBABILITY; 344150514bd03312ab0a890cc040019cfbc73eb077cAmith Yamasani } 34526af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani 34626af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani @Override 34726af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani public int getFrequency(final String word) { 348390989da1967f9d385212cd2e22a50589ce69046Amith Yamasani if (TextUtils.isEmpty(word)) return NOT_A_PROBABILITY; 349390989da1967f9d385212cd2e22a50589ce69046Amith Yamasani int[] codePoints = StringUtils.toCodePointArray(word); 350390989da1967f9d385212cd2e22a50589ce69046Amith Yamasani return getProbabilityNative(mNativeDict, codePoints); 351390989da1967f9d385212cd2e22a50589ce69046Amith Yamasani } 352390989da1967f9d385212cd2e22a50589ce69046Amith Yamasani 353390989da1967f9d385212cd2e22a50589ce69046Amith Yamasani @Override 35426af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani public int getMaxFrequencyOfExactMatches(final String word) { 355c34dc7cdeb5cae8ca4c731838aafe90ed4c9a2b8Amith Yamasani if (TextUtils.isEmpty(word)) return NOT_A_PROBABILITY; 35626af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani int[] codePoints = StringUtils.toCodePointArray(word); 35726af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani return getMaxProbabilityOfExactMatchesNative(mNativeDict, codePoints); 35826af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani } 3599f6c25f57e26f3e2f9c744547a139d14b7d3db5cAmith Yamasani 3609f6c25f57e26f3e2f9c744547a139d14b7d3db5cAmith Yamasani @UsedForTesting 3619f6c25f57e26f3e2f9c744547a139d14b7d3db5cAmith Yamasani public boolean isValidNgram(final PrevWordsInfo prevWordsInfo, final String word) { 362390989da1967f9d385212cd2e22a50589ce69046Amith Yamasani return getNgramProbability(prevWordsInfo, word) != NOT_A_PROBABILITY; 3639f6c25f57e26f3e2f9c744547a139d14b7d3db5cAmith Yamasani } 3641c7c319bb89b9988bfd12afc3e8d89449fd163fcJason Monk 3652cc03e5606ad7cd473283898400506d5ac2237baJeff Sharkey public int getNgramProbability(final PrevWordsInfo prevWordsInfo, final String word) { 3662cc03e5606ad7cd473283898400506d5ac2237baJeff Sharkey if (!prevWordsInfo.isValid() || TextUtils.isEmpty(word)) { 3672cc03e5606ad7cd473283898400506d5ac2237baJeff Sharkey return NOT_A_PROBABILITY; 3682cc03e5606ad7cd473283898400506d5ac2237baJeff Sharkey } 3692cc03e5606ad7cd473283898400506d5ac2237baJeff Sharkey final int[] codePoints0 = StringUtils.toCodePointArray(prevWordsInfo.mPrevWord); 3702cc03e5606ad7cd473283898400506d5ac2237baJeff Sharkey final int[] codePoints1 = StringUtils.toCodePointArray(word); 3712cc03e5606ad7cd473283898400506d5ac2237baJeff Sharkey return getBigramProbabilityNative(mNativeDict, codePoints0, 3722cc03e5606ad7cd473283898400506d5ac2237baJeff Sharkey prevWordsInfo.mIsBeginningOfSentence, codePoints1); 3732cc03e5606ad7cd473283898400506d5ac2237baJeff Sharkey } 3742cc03e5606ad7cd473283898400506d5ac2237baJeff Sharkey 3752cc03e5606ad7cd473283898400506d5ac2237baJeff Sharkey public WordProperty getWordProperty(final String word) { 3762cc03e5606ad7cd473283898400506d5ac2237baJeff Sharkey if (TextUtils.isEmpty(word)) { 37726af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani return null; 3781c7c319bb89b9988bfd12afc3e8d89449fd163fcJason Monk } 3791c7c319bb89b9988bfd12afc3e8d89449fd163fcJason Monk final int[] codePoints = StringUtils.toCodePointArray(word); 3801c7c319bb89b9988bfd12afc3e8d89449fd163fcJason Monk final int[] outCodePoints = new int[MAX_WORD_LENGTH]; 3811c7c319bb89b9988bfd12afc3e8d89449fd163fcJason Monk final boolean[] outFlags = new boolean[FORMAT_WORD_PROPERTY_OUTPUT_FLAG_COUNT]; 3821c7c319bb89b9988bfd12afc3e8d89449fd163fcJason Monk final int[] outProbabilityInfo = 3831c7c319bb89b9988bfd12afc3e8d89449fd163fcJason Monk new int[FORMAT_WORD_PROPERTY_OUTPUT_PROBABILITY_INFO_COUNT]; 3841c7c319bb89b9988bfd12afc3e8d89449fd163fcJason Monk final ArrayList<int[]> outBigramTargets = new ArrayList<>(); 3851c7c319bb89b9988bfd12afc3e8d89449fd163fcJason Monk final ArrayList<int[]> outBigramProbabilityInfo = new ArrayList<>(); 386c34dc7cdeb5cae8ca4c731838aafe90ed4c9a2b8Amith Yamasani final ArrayList<int[]> outShortcutTargets = new ArrayList<>(); 387c34dc7cdeb5cae8ca4c731838aafe90ed4c9a2b8Amith Yamasani final ArrayList<Integer> outShortcutProbabilities = new ArrayList<>(); 38826af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani getWordPropertyNative(mNativeDict, codePoints, outCodePoints, outFlags, outProbabilityInfo, 38926af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani outBigramTargets, outBigramProbabilityInfo, outShortcutTargets, 39026af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani outShortcutProbabilities); 3911c7c319bb89b9988bfd12afc3e8d89449fd163fcJason Monk return new WordProperty(codePoints, 3921c7c319bb89b9988bfd12afc3e8d89449fd163fcJason Monk outFlags[FORMAT_WORD_PROPERTY_IS_NOT_A_WORD_INDEX], 3931c7c319bb89b9988bfd12afc3e8d89449fd163fcJason Monk outFlags[FORMAT_WORD_PROPERTY_IS_BLACKLISTED_INDEX], 3941c7c319bb89b9988bfd12afc3e8d89449fd163fcJason Monk outFlags[FORMAT_WORD_PROPERTY_HAS_BIGRAMS_INDEX], 3951c7c319bb89b9988bfd12afc3e8d89449fd163fcJason Monk outFlags[FORMAT_WORD_PROPERTY_HAS_SHORTCUTS_INDEX], outProbabilityInfo, 396f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot outBigramTargets, outBigramProbabilityInfo, outShortcutTargets, 39726af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani outShortcutProbabilities); 398f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot } 399f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot 400f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot public static class GetNextWordPropertyResult { 40126af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani public WordProperty mWordProperty; 40226af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani public int mNextToken; 40326af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani 404f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot public GetNextWordPropertyResult(final WordProperty wordProperty, final int nextToken) { 405f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot mWordProperty = wordProperty; 406f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot mNextToken = nextToken; 407f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot } 408f1939901d2ed0480069f0b23be64f122fce93995Nicolas Prevot } 40926af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani 41026af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani /** 41126af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani * Method to iterate all words in the dictionary for makedict. 41226af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani * If token is 0, this method newly starts iterating the dictionary. 41326af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani */ 41426af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani public GetNextWordPropertyResult getNextWordProperty(final int token) { 41526af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani final int[] codePoints = new int[MAX_WORD_LENGTH]; 41626af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani final int nextToken = getNextWordNative(mNativeDict, token, codePoints); 41726af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani final String word = StringUtils.getStringFromNullTerminatedCodePointArray(codePoints); 41826af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani return new GetNextWordPropertyResult(getWordProperty(word), nextToken); 41926af829fd70609cf073b56e54e1f78faf83a5e8bAmith Yamasani } 42053d63dcd04da3c1d5187b29f6530c2dcac9d516cSander Alewijnse 421f3ece36535d4999cf2bfd2175a33da6c3cdf298eBenjamin Franz // Add a unigram entry to binary dictionary with unigram attributes in native code. 422f3ece36535d4999cf2bfd2175a33da6c3cdf298eBenjamin Franz public boolean addUnigramEntry(final String word, final int probability, 423f3ece36535d4999cf2bfd2175a33da6c3cdf298eBenjamin Franz final String shortcutTarget, final int shortcutProbability, 424f3ece36535d4999cf2bfd2175a33da6c3cdf298eBenjamin Franz final boolean isBeginningOfSentence, final boolean isNotAWord, 425f3ece36535d4999cf2bfd2175a33da6c3cdf298eBenjamin Franz final boolean isBlacklisted, final int timestamp) { 426f3ece36535d4999cf2bfd2175a33da6c3cdf298eBenjamin Franz if (word == null || (word.isEmpty() && !isBeginningOfSentence)) { 427f3ece36535d4999cf2bfd2175a33da6c3cdf298eBenjamin Franz return false; 428f3ece36535d4999cf2bfd2175a33da6c3cdf298eBenjamin Franz } 429f3ece36535d4999cf2bfd2175a33da6c3cdf298eBenjamin Franz final int[] codePoints = StringUtils.toCodePointArray(word); 430bff46bac807ae8a9ebdc22c449a8d4f78711b4d2Benjamin Franz final int[] shortcutTargetCodePoints = (shortcutTarget != null) ? 431bff46bac807ae8a9ebdc22c449a8d4f78711b4d2Benjamin Franz StringUtils.toCodePointArray(shortcutTarget) : null; 432bff46bac807ae8a9ebdc22c449a8d4f78711b4d2Benjamin Franz if (!addUnigramWordNative(mNativeDict, codePoints, probability, shortcutTargetCodePoints, 433bff46bac807ae8a9ebdc22c449a8d4f78711b4d2Benjamin Franz shortcutProbability, isBeginningOfSentence, isNotAWord, isBlacklisted, timestamp)) { 434bff46bac807ae8a9ebdc22c449a8d4f78711b4d2Benjamin Franz return false; 435bff46bac807ae8a9ebdc22c449a8d4f78711b4d2Benjamin Franz } 436bff46bac807ae8a9ebdc22c449a8d4f78711b4d2Benjamin Franz mHasUpdated = true; 437bff46bac807ae8a9ebdc22c449a8d4f78711b4d2Benjamin Franz return true; 438bff46bac807ae8a9ebdc22c449a8d4f78711b4d2Benjamin Franz } 439bff46bac807ae8a9ebdc22c449a8d4f78711b4d2Benjamin Franz 440bff46bac807ae8a9ebdc22c449a8d4f78711b4d2Benjamin Franz // Remove a unigram entry from the binary dictionary in native code. 441bff46bac807ae8a9ebdc22c449a8d4f78711b4d2Benjamin Franz public boolean removeUnigramEntry(final String word) { 442b501330a1b6ef14ff512a5727f7a01bc423d6fbbFyodor Kupolov if (TextUtils.isEmpty(word)) { 443b501330a1b6ef14ff512a5727f7a01bc423d6fbbFyodor Kupolov return false; 444b501330a1b6ef14ff512a5727f7a01bc423d6fbbFyodor Kupolov } 445b501330a1b6ef14ff512a5727f7a01bc423d6fbbFyodor Kupolov final int[] codePoints = StringUtils.toCodePointArray(word); 446b501330a1b6ef14ff512a5727f7a01bc423d6fbbFyodor Kupolov if (!removeUnigramWordNative(mNativeDict, codePoints)) { 447b501330a1b6ef14ff512a5727f7a01bc423d6fbbFyodor Kupolov return false; 448b501330a1b6ef14ff512a5727f7a01bc423d6fbbFyodor Kupolov } 449b501330a1b6ef14ff512a5727f7a01bc423d6fbbFyodor Kupolov mHasUpdated = true; 450b501330a1b6ef14ff512a5727f7a01bc423d6fbbFyodor Kupolov return true; 451b501330a1b6ef14ff512a5727f7a01bc423d6fbbFyodor Kupolov } 4529edbda18df025527e18614cf0c45d538a27af30fNicolas Prevot 4539edbda18df025527e18614cf0c45d538a27af30fNicolas Prevot // Add an n-gram entry to the binary dictionary with timestamp in native code. 4549edbda18df025527e18614cf0c45d538a27af30fNicolas Prevot public boolean addNgramEntry(final PrevWordsInfo prevWordsInfo, final String word, 4559edbda18df025527e18614cf0c45d538a27af30fNicolas Prevot final int probability, final int timestamp) { 4569edbda18df025527e18614cf0c45d538a27af30fNicolas Prevot if (!prevWordsInfo.isValid() || TextUtils.isEmpty(word)) { 4579edbda18df025527e18614cf0c45d538a27af30fNicolas Prevot return false; 4589edbda18df025527e18614cf0c45d538a27af30fNicolas Prevot } 4599edbda18df025527e18614cf0c45d538a27af30fNicolas Prevot final int[] codePoints0 = StringUtils.toCodePointArray(prevWordsInfo.mPrevWord); 4609edbda18df025527e18614cf0c45d538a27af30fNicolas Prevot final int[] codePoints1 = StringUtils.toCodePointArray(word); 4619edbda18df025527e18614cf0c45d538a27af30fNicolas Prevot if (!addBigramWordsNative(mNativeDict, codePoints0, prevWordsInfo.mIsBeginningOfSentence, 4629edbda18df025527e18614cf0c45d538a27af30fNicolas Prevot codePoints1, probability, timestamp)) { 4639edbda18df025527e18614cf0c45d538a27af30fNicolas Prevot return false; 4649edbda18df025527e18614cf0c45d538a27af30fNicolas Prevot } 4659edbda18df025527e18614cf0c45d538a27af30fNicolas Prevot mHasUpdated = true; 4669edbda18df025527e18614cf0c45d538a27af30fNicolas Prevot return true; 4679edbda18df025527e18614cf0c45d538a27af30fNicolas Prevot } 46853d63dcd04da3c1d5187b29f6530c2dcac9d516cSander Alewijnse 46953d63dcd04da3c1d5187b29f6530c2dcac9d516cSander Alewijnse // Remove an n-gram entry from the binary dictionary in native code. 47053d63dcd04da3c1d5187b29f6530c2dcac9d516cSander Alewijnse public boolean removeNgramEntry(final PrevWordsInfo prevWordsInfo, final String word) { 47153d63dcd04da3c1d5187b29f6530c2dcac9d516cSander Alewijnse if (!prevWordsInfo.isValid() || TextUtils.isEmpty(word)) { 47253d63dcd04da3c1d5187b29f6530c2dcac9d516cSander Alewijnse return false; 47353d63dcd04da3c1d5187b29f6530c2dcac9d516cSander Alewijnse } 47453d63dcd04da3c1d5187b29f6530c2dcac9d516cSander Alewijnse final int[] codePoints0 = StringUtils.toCodePointArray(prevWordsInfo.mPrevWord); 47553d63dcd04da3c1d5187b29f6530c2dcac9d516cSander Alewijnse final int[] codePoints1 = StringUtils.toCodePointArray(word); 47653d63dcd04da3c1d5187b29f6530c2dcac9d516cSander Alewijnse if (!removeBigramWordsNative(mNativeDict, codePoints0, prevWordsInfo.mIsBeginningOfSentence, 47753d63dcd04da3c1d5187b29f6530c2dcac9d516cSander Alewijnse codePoints1)) { 47853d63dcd04da3c1d5187b29f6530c2dcac9d516cSander Alewijnse return false; 47953d63dcd04da3c1d5187b29f6530c2dcac9d516cSander Alewijnse } 480b14ed95647ff7c38869550606396d5b784eeece1Nicolas Prevot mHasUpdated = true; 481b14ed95647ff7c38869550606396d5b784eeece1Nicolas Prevot return true; 482b14ed95647ff7c38869550606396d5b784eeece1Nicolas Prevot } 483b14ed95647ff7c38869550606396d5b784eeece1Nicolas Prevot 48453d63dcd04da3c1d5187b29f6530c2dcac9d516cSander Alewijnse public void addMultipleDictionaryEntries(final LanguageModelParam[] languageModelParams) { 48553d63dcd04da3c1d5187b29f6530c2dcac9d516cSander Alewijnse if (!isValidDictionary()) return; 48653d63dcd04da3c1d5187b29f6530c2dcac9d516cSander Alewijnse int processedParamCount = 0; 487655d0e2029e6ae77a47e922dce4c4989818b8dd1Amith Yamasani while (processedParamCount < languageModelParams.length) { 488655d0e2029e6ae77a47e922dce4c4989818b8dd1Amith Yamasani if (needsToRunGC(true /* mindsBlockByGC */)) { 489655d0e2029e6ae77a47e922dce4c4989818b8dd1Amith Yamasani flushWithGC(); 490655d0e2029e6ae77a47e922dce4c4989818b8dd1Amith Yamasani } 491655d0e2029e6ae77a47e922dce4c4989818b8dd1Amith Yamasani processedParamCount = addMultipleDictionaryEntriesNative(mNativeDict, 492655d0e2029e6ae77a47e922dce4c4989818b8dd1Amith Yamasani languageModelParams, processedParamCount); 493655d0e2029e6ae77a47e922dce4c4989818b8dd1Amith Yamasani mHasUpdated = true; 49427db46850b708070452c0ce49daf5f79503fbde6Amith Yamasani if (processedParamCount <= 0) { 49527db46850b708070452c0ce49daf5f79503fbde6Amith Yamasani return; 4967e99bc02c8e2f44dd92d70bfa6e654297e5286d8Amith Yamasani } 49727db46850b708070452c0ce49daf5f79503fbde6Amith Yamasani } 49827db46850b708070452c0ce49daf5f79503fbde6Amith Yamasani } 49927db46850b708070452c0ce49daf5f79503fbde6Amith Yamasani 50027db46850b708070452c0ce49daf5f79503fbde6Amith Yamasani private void reopen() { 50127db46850b708070452c0ce49daf5f79503fbde6Amith Yamasani close(); 50227db46850b708070452c0ce49daf5f79503fbde6Amith Yamasani final File dictFile = new File(mDictFilePath); 503a12fccf57d5ec289793699d9b22ff45daccd3933Maggie Benthall // WARNING: Because we pass 0 as the offset and file.length() as the length, this can 504258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani // only be called for actual files. Right now it's only called by the flush() family of 505258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani // functions, which require an updatable dictionary, so it's okay. But beware. 506258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani loadDictionary(dictFile.getAbsolutePath(), 0 /* startOffset */, 507258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani dictFile.length(), mIsUpdatable); 508258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani } 509258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani 510258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani // Flush to dict file if the dictionary has been updated. 511258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani public boolean flush() { 5121a447535cef7e3739d5f763dfe13e568568b9789Kenny Guy if (!isValidDictionary()) return false; 513e928d7d95dbb64627e6ff3a0572190c555b59d96Amith Yamasani if (mHasUpdated) { 514258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani if (!flushNative(mNativeDict, mDictFilePath)) { 5154673e7ea8d1f869910a9c0f9c211d4d27ad50b41Jeff Sharkey return false; 5161a447535cef7e3739d5f763dfe13e568568b9789Kenny Guy } 5171a447535cef7e3739d5f763dfe13e568568b9789Kenny Guy reopen(); 5181a447535cef7e3739d5f763dfe13e568568b9789Kenny Guy } 519258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani return true; 520258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani } 5216794458f8626c3be27eac3db3a5c89d94f132675Maggie Benthall 5225760e1786bcc2feac9d1c2c784520aa4d6cf8cb8Amith Yamasani // Run GC and flush to dict file if the dictionary has been updated. 523be81c800ae6216e30b6008b4c73172b36531c405Jessica Hummel public boolean flushWithGCIfHasUpdated() { 5245760e1786bcc2feac9d1c2c784520aa4d6cf8cb8Amith Yamasani if (mHasUpdated) { 525258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani return flushWithGC(); 5266794458f8626c3be27eac3db3a5c89d94f132675Maggie Benthall } 527258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani return true; 52879af1dd54c16cde063152922b42c96d72ae9eca8Dianne Hackborn } 529258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani 530258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani // Run GC and flush to dict file. 531258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani public boolean flushWithGC() { 5328832c18d8b63367929c2d394c9c508f56003d400Dianne Hackborn if (!isValidDictionary()) return false; 5338832c18d8b63367929c2d394c9c508f56003d400Dianne Hackborn if (!flushWithGCNative(mNativeDict, mDictFilePath)) { 5348832c18d8b63367929c2d394c9c508f56003d400Dianne Hackborn return false; 535258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani } 536258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani reopen(); 537258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani return true; 538258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani } 539258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani 540258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani /** 541258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani * Checks whether GC is needed to run or not. 542258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani * @param mindsBlockByGC Whether to mind operations blocked by GC. We don't need to care about 543258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani * the blocking in some situations such as in idle time or just before closing. 544258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani * @return whether GC is needed to run or not. 545258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani */ 54667a101aa3006aa2011a9d9edaacb2fa6f6f31140Dianne Hackborn public boolean needsToRunGC(final boolean mindsBlockByGC) { 547e4ab16ad98b183afbf7a21ad7314372de41a8b57Dan Morrill if (!isValidDictionary()) return false; 548e4ab16ad98b183afbf7a21ad7314372de41a8b57Dan Morrill return needsToRunGCNative(mNativeDict, mindsBlockByGC); 54967a101aa3006aa2011a9d9edaacb2fa6f6f31140Dianne Hackborn } 550955d8d69ea6caabce1461dc25b339b9bf9dc61a6Dianne Hackborn 55167a101aa3006aa2011a9d9edaacb2fa6f6f31140Dianne Hackborn public boolean migrateTo(final int newFormatVersion) { 55267a101aa3006aa2011a9d9edaacb2fa6f6f31140Dianne Hackborn if (!isValidDictionary()) { 55367a101aa3006aa2011a9d9edaacb2fa6f6f31140Dianne Hackborn return false; 554e4ab16ad98b183afbf7a21ad7314372de41a8b57Dan Morrill } 555e4ab16ad98b183afbf7a21ad7314372de41a8b57Dan Morrill final String tmpDictFilePath = mDictFilePath + DICT_FILE_NAME_SUFFIX_FOR_MIGRATION; 556988ae30ff7729ac0e9a44ee665c7e00f1961e7cdAdam Powell if (!migrateNative(mNativeDict, tmpDictFilePath, newFormatVersion)) { 557988ae30ff7729ac0e9a44ee665c7e00f1961e7cdAdam Powell return false; 558e4ab16ad98b183afbf7a21ad7314372de41a8b57Dan Morrill } 559df2e92a535e19c00edd37318d974dab992ccc2c1Amith Yamasani close(); 560df2e92a535e19c00edd37318d974dab992ccc2c1Amith Yamasani final File dictFile = new File(mDictFilePath); 5615760e1786bcc2feac9d1c2c784520aa4d6cf8cb8Amith Yamasani final File tmpDictFile = new File(tmpDictFilePath); 5625760e1786bcc2feac9d1c2c784520aa4d6cf8cb8Amith Yamasani if (!FileUtils.deleteRecursively(dictFile)) { 5635760e1786bcc2feac9d1c2c784520aa4d6cf8cb8Amith Yamasani return false; 5645760e1786bcc2feac9d1c2c784520aa4d6cf8cb8Amith Yamasani } 5655760e1786bcc2feac9d1c2c784520aa4d6cf8cb8Amith Yamasani if (!BinaryDictionaryUtils.renameDict(tmpDictFile, dictFile)) { 5665760e1786bcc2feac9d1c2c784520aa4d6cf8cb8Amith Yamasani return false; 5675760e1786bcc2feac9d1c2c784520aa4d6cf8cb8Amith Yamasani } 5685760e1786bcc2feac9d1c2c784520aa4d6cf8cb8Amith Yamasani loadDictionary(dictFile.getAbsolutePath(), 0 /* startOffset */, 5695760e1786bcc2feac9d1c2c784520aa4d6cf8cb8Amith Yamasani dictFile.length(), mIsUpdatable); 5705760e1786bcc2feac9d1c2c784520aa4d6cf8cb8Amith Yamasani return true; 5715760e1786bcc2feac9d1c2c784520aa4d6cf8cb8Amith Yamasani } 572e1375908a5f05e5c926e95049970c4505e4dfad9Amith Yamasani 57346bc4ebb87232b39d7b02ac0135c8ccf2c33f233Amith Yamasani @UsedForTesting 574e1375908a5f05e5c926e95049970c4505e4dfad9Amith Yamasani public String getPropertyForTest(final String query) { 5752555dafce87e60fae28d71913730abf73e40fcd7Amith Yamasani if (!isValidDictionary()) return ""; 576df2e92a535e19c00edd37318d974dab992ccc2c1Amith Yamasani return getPropertyNative(mNativeDict, query); 577e1375908a5f05e5c926e95049970c4505e4dfad9Amith Yamasani } 578df2e92a535e19c00edd37318d974dab992ccc2c1Amith Yamasani 57971e6c697e54a43d357cc25d87a446d140f17396aAmith Yamasani @Override 580df2e92a535e19c00edd37318d974dab992ccc2c1Amith Yamasani public boolean shouldAutoCommit(final SuggestedWordInfo candidate) { 58146bc4ebb87232b39d7b02ac0135c8ccf2c33f233Amith Yamasani return candidate.mAutoCommitFirstWordConfidence > CONFIDENCE_TO_AUTO_COMMIT; 582df2e92a535e19c00edd37318d974dab992ccc2c1Amith Yamasani } 583df2e92a535e19c00edd37318d974dab992ccc2c1Amith Yamasani 584df2e92a535e19c00edd37318d974dab992ccc2c1Amith Yamasani @Override 585df2e92a535e19c00edd37318d974dab992ccc2c1Amith Yamasani public void close() { 586258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani synchronized (mDicTraverseSessions) { 5871e9c21871e81642669079cd290ef47818a3165bdAmith Yamasani final int sessionsSize = mDicTraverseSessions.size(); 5881e9c21871e81642669079cd290ef47818a3165bdAmith Yamasani for (int index = 0; index < sessionsSize; ++index) { 5891e9c21871e81642669079cd290ef47818a3165bdAmith Yamasani final DicTraverseSession traverseSession = mDicTraverseSessions.valueAt(index); 5901e9c21871e81642669079cd290ef47818a3165bdAmith Yamasani if (traverseSession != null) { 5911e9c21871e81642669079cd290ef47818a3165bdAmith Yamasani traverseSession.close(); 5921e9c21871e81642669079cd290ef47818a3165bdAmith Yamasani } 5931e9c21871e81642669079cd290ef47818a3165bdAmith Yamasani } 5941e9c21871e81642669079cd290ef47818a3165bdAmith Yamasani mDicTraverseSessions.clear(); 5951e9c21871e81642669079cd290ef47818a3165bdAmith Yamasani } 5961e9c21871e81642669079cd290ef47818a3165bdAmith Yamasani closeInternalLocked(); 5970e8d7d63ba439cc0604af7055679dae3d30fdc48Amith Yamasani } 5980e8d7d63ba439cc0604af7055679dae3d30fdc48Amith Yamasani 5990e8d7d63ba439cc0604af7055679dae3d30fdc48Amith Yamasani private synchronized void closeInternalLocked() { 6000e8d7d63ba439cc0604af7055679dae3d30fdc48Amith Yamasani if (mNativeDict != 0) { 6010e8d7d63ba439cc0604af7055679dae3d30fdc48Amith Yamasani closeNative(mNativeDict); 6020e8d7d63ba439cc0604af7055679dae3d30fdc48Amith Yamasani mNativeDict = 0; 6030e8d7d63ba439cc0604af7055679dae3d30fdc48Amith Yamasani } 6040e8d7d63ba439cc0604af7055679dae3d30fdc48Amith Yamasani } 6050e8d7d63ba439cc0604af7055679dae3d30fdc48Amith Yamasani 6060e8d7d63ba439cc0604af7055679dae3d30fdc48Amith Yamasani // TODO: Manage BinaryDictionary instances without using WeakReference or something. 6070e8d7d63ba439cc0604af7055679dae3d30fdc48Amith Yamasani @Override 6080e8d7d63ba439cc0604af7055679dae3d30fdc48Amith Yamasani protected void finalize() throws Throwable { 6090e8d7d63ba439cc0604af7055679dae3d30fdc48Amith Yamasani try { 610a8a9bd65bf5865d83ef44f54552ca39522bfbcf0Dianne Hackborn closeInternalLocked(); 611a8a9bd65bf5865d83ef44f54552ca39522bfbcf0Dianne Hackborn } finally { 612a8a9bd65bf5865d83ef44f54552ca39522bfbcf0Dianne Hackborn super.finalize(); 613a8a9bd65bf5865d83ef44f54552ca39522bfbcf0Dianne Hackborn } 614a8a9bd65bf5865d83ef44f54552ca39522bfbcf0Dianne Hackborn } 615a8a9bd65bf5865d83ef44f54552ca39522bfbcf0Dianne Hackborn} 616a8a9bd65bf5865d83ef44f54552ca39522bfbcf0Dianne Hackborn