BinaryDictionary.java revision 860a9f85ff7f2753b7e1bed2e00f86de8eca68e1
1923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project/* 2443c360d0afdbab091994244f045f4756feaf2b4Jean-Baptiste Queru * Copyright (C) 2008 The Android Open Source Project 3e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa * 4923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * use this file except in compliance with the License. You may obtain a copy of 6923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * the License at 7e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa * 8923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 9e90b333017c68e888a5e3d351f07ea29036457d0Ken Wakasa * 10923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 11923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * License for the specific language governing permissions and limitations under 14923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * the License. 15923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 16923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 17923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectpackage com.android.inputmethod.latin; 18923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 19fa086c90760bc2bedf0b74eacb0fed3bf7ebc2b7Tadashi G. Takaokaimport android.content.Context; 204d289d39aeae21064f63d958974816ceee3e9fdeTom Ouyangimport android.text.TextUtils; 21fa086c90760bc2bedf0b74eacb0fed3bf7ebc2b7Tadashi G. Takaoka 22ab72a97d7ce44230a0c824797d1675a5ca354a56Tadashi G. Takaokaimport com.android.inputmethod.keyboard.ProximityInfo; 23bda7eaa63aace64f3d40eae3affaf281591ffa66Jean Chalardimport com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; 24ab72a97d7ce44230a0c824797d1675a5ca354a56Tadashi G. Takaoka 25bda7eaa63aace64f3d40eae3affaf281591ffa66Jean Chalardimport java.util.ArrayList; 26923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport java.util.Arrays; 2743ebd8a035af31244a2d54fce5d8000a1fbada4csatokimport java.util.Locale; 28923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 29923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project/** 30923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Implements a static, compacted, binary dictionary of standard words. 31923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 32923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectpublic class BinaryDictionary extends Dictionary { 33923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 34cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard public static final String DICTIONARY_PACK_AUTHORITY = 35cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard "com.android.inputmethod.latin.dictionarypack"; 36cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard 37979f8690967ff5409fe18f5085858ccdb8e0ccf1satok /** 38cba93f50c3d46ada773ec49435689dc3e2094385Jean Chalard * There is a difference between what java and native code can handle. 39979f8690967ff5409fe18f5085858ccdb8e0ccf1satok * This value should only be used in BinaryDictionary.java 40979f8690967ff5409fe18f5085858ccdb8e0ccf1satok * It is necessary to keep it at this value because some languages e.g. German have 41979f8690967ff5409fe18f5085858ccdb8e0ccf1satok * really long words. 42979f8690967ff5409fe18f5085858ccdb8e0ccf1satok */ 438fbd55229243cb66c03d5ea1f79dfb39f596590dsatok public static final int MAX_WORD_LENGTH = 48; 442e04770adfc16344f69d316efd3ed0a617ede330Tadashi G. Takaoka public static final int MAX_WORDS = 18; 4573680097996ea2ddbca3f84144a00ce3ba66b763Satoshi Kataoka public static final int MAX_SPACES = 16; 46979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 47979f8690967ff5409fe18f5085858ccdb8e0ccf1satok private static final String TAG = "BinaryDictionary"; 48979f8690967ff5409fe18f5085858ccdb8e0ccf1satok private static final int MAX_BIGRAMS = 60; 496f233f7ba1ee924844154515dda208bb9b34acb5Jean Chalard private static final int MAX_RESULTS = MAX_BIGRAMS > MAX_WORDS ? MAX_BIGRAMS : MAX_WORDS; 50923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 51923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project private static final int TYPED_LETTER_MULTIPLIER = 2; 52923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 535fdcd7d5cd9d39d41568aa1412a4b1a866c05d3aTadashi G. Takaoka private long mNativeDict; 546ba8de2a608dfe4865b0b59a753f2d2abbedeeffsatok private final int[] mInputCodes = new int[MAX_WORD_LENGTH]; 556f233f7ba1ee924844154515dda208bb9b34acb5Jean Chalard private final char[] mOutputChars = new char[MAX_WORD_LENGTH * MAX_RESULTS]; 5673680097996ea2ddbca3f84144a00ce3ba66b763Satoshi Kataoka private final int[] mSpaceIndices = new int[MAX_SPACES]; 576f233f7ba1ee924844154515dda208bb9b34acb5Jean Chalard private final int[] mOutputScores = new int[MAX_RESULTS]; 58923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 59338d3ec725a952cbe603ac8b2d49c337463f4093Jean Chalard private final boolean mUseFullEditDistance; 60923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 61923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 624250eb27f54f8fedc388fe4825b0646a88778744Jean Chalard * Constructor for the binary dictionary. This is supposed to be called from the 634250eb27f54f8fedc388fe4825b0646a88778744Jean Chalard * dictionary factory. 644250eb27f54f8fedc388fe4825b0646a88778744Jean Chalard * All implementations should pass null into flagArray, except for testing purposes. 654250eb27f54f8fedc388fe4825b0646a88778744Jean Chalard * @param context the context to access the environment from. 664250eb27f54f8fedc388fe4825b0646a88778744Jean Chalard * @param filename the name of the file to read through native code. 674250eb27f54f8fedc388fe4825b0646a88778744Jean Chalard * @param offset the offset of the dictionary data within the file. 684250eb27f54f8fedc388fe4825b0646a88778744Jean Chalard * @param length the length of the binary data. 6924aee9100e92dc4c06cdb54487a4922420fa8660Jean Chalard * @param useFullEditDistance whether to use the full edit distance in suggestions 7005efe576f976f5fa280f8d523f2935c15cbb9bd1Jean Chalard * @param dictType the dictionary type, as a human-readable string 71923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 724250eb27f54f8fedc388fe4825b0646a88778744Jean Chalard public BinaryDictionary(final Context context, 7324aee9100e92dc4c06cdb54487a4922420fa8660Jean Chalard final String filename, final long offset, final long length, 7405efe576f976f5fa280f8d523f2935c15cbb9bd1Jean Chalard final boolean useFullEditDistance, final Locale locale, final String dictType) { 7505efe576f976f5fa280f8d523f2935c15cbb9bd1Jean Chalard super(dictType); 76338d3ec725a952cbe603ac8b2d49c337463f4093Jean Chalard mUseFullEditDistance = useFullEditDistance; 774250eb27f54f8fedc388fe4825b0646a88778744Jean Chalard loadDictionary(filename, offset, length); 78979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 79979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 80eaef1c500703b4ee378821884c7b108815ed2983Ken Wakasa static { 81cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka JniUtils.loadNativeLibrary(); 82eaef1c500703b4ee378821884c7b108815ed2983Ken Wakasa } 83c2bbc6a4499a6da979381fa0e8e6e855a5ac6aa4Jean Chalard 845fdcd7d5cd9d39d41568aa1412a4b1a866c05d3aTadashi G. Takaoka private native long openNative(String sourceDir, long dictOffset, long dictSize, 856ba8de2a608dfe4865b0b59a753f2d2abbedeeffsatok int typedLetterMultiplier, int fullWordMultiplier, int maxWordLength, int maxWords); 865fdcd7d5cd9d39d41568aa1412a4b1a866c05d3aTadashi G. Takaoka private native void closeNative(long dict); 872f854e170c9fde47cae804145f90d164cdb5ceb8Satoshi Kataoka private native int getFrequencyNative(long dict, int[] word, int wordLength); 884d289d39aeae21064f63d958974816ceee3e9fdeTom Ouyang private native boolean isValidBigramNative(long dict, int[] word1, int[] word2); 895fdcd7d5cd9d39d41568aa1412a4b1a866c05d3aTadashi G. Takaoka private native int getSuggestionsNative(long dict, long proximityInfo, int[] xCoordinates, 9073680097996ea2ddbca3f84144a00ce3ba66b763Satoshi Kataoka int[] yCoordinates, int[] times, int[] pointerIds, int[] inputCodes, int codesSize, 9105efe576f976f5fa280f8d523f2935c15cbb9bd1Jean Chalard int commitPoint, boolean isGesture, 9273680097996ea2ddbca3f84144a00ce3ba66b763Satoshi Kataoka int[] prevWordCodePointArray, boolean useFullEditDistance, char[] outputChars, 9373680097996ea2ddbca3f84144a00ce3ba66b763Satoshi Kataoka int[] scores, int[] outputIndices); 94522a04ea5b249d0af556647d2abcad57e5b99b4fJean Chalard private native int getBigramsNative(long dict, int[] prevWord, int prevWordLength, 95e7a2512aa3666e1b891dc7dfc5a0cb28fd66bea9Tadashi G. Takaoka int[] inputCodes, int inputCodesLength, char[] outputChars, int[] scores, 966ba8de2a608dfe4865b0b59a753f2d2abbedeeffsatok int maxWordLength, int maxBigrams); 970028ed3627ff4f37a62a80f3b2c857e373cd5090satok private static native float calcNormalizedScoreNative( 98be0cf72253f15bff6abdeaa79f60a56f06ab7b86satok char[] before, int beforeLength, char[] after, int afterLength, int score); 99be0cf72253f15bff6abdeaa79f60a56f06ab7b86satok private static native int editDistanceNative( 100be0cf72253f15bff6abdeaa79f60a56f06ab7b86satok char[] before, int beforeLength, char[] after, int afterLength); 101979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 10233e0b1e79e464ac48a09433bbfcbb17ded620452Tadashi G. Takaoka private final void loadDictionary(String path, long startOffset, long length) { 10333e0b1e79e464ac48a09433bbfcbb17ded620452Tadashi G. Takaoka mNativeDict = openNative(path, startOffset, length, 1046ba8de2a608dfe4865b0b59a753f2d2abbedeeffsatok TYPED_LETTER_MULTIPLIER, FULL_WORD_SCORE_MULTIPLIER, MAX_WORD_LENGTH, MAX_WORDS); 105979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 106979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 107979f8690967ff5409fe18f5085858ccdb8e0ccf1satok @Override 108b30d2185f24e3d531f5d46249e7c97391705e469Jean Chalard public ArrayList<SuggestedWordInfo> getSuggestions(final WordComposer composer, 109b30d2185f24e3d531f5d46249e7c97391705e469Jean Chalard final CharSequence prevWord, final ProximityInfo proximityInfo) { 110b4b93dbf3e0912ba26c5c34abba7a5b94c74138cJean Chalard if (!isValidDictionary()) return null; 111b4b93dbf3e0912ba26c5c34abba7a5b94c74138cJean Chalard Arrays.fill(mInputCodes, WordComposer.NOT_A_CODE); 112b4b93dbf3e0912ba26c5c34abba7a5b94c74138cJean Chalard Arrays.fill(mOutputChars, (char) 0); 113b4b93dbf3e0912ba26c5c34abba7a5b94c74138cJean Chalard Arrays.fill(mOutputScores, 0); 114ea98e026f1ad7732279aec6d06107f46ea0af93dJean Chalard // TODO: toLowerCase in the native code 115ea98e026f1ad7732279aec6d06107f46ea0af93dJean Chalard final int[] prevWordCodePointArray = (null == prevWord) 116ea98e026f1ad7732279aec6d06107f46ea0af93dJean Chalard ? null : StringUtils.toCodePointArray(prevWord.toString()); 117860a9f85ff7f2753b7e1bed2e00f86de8eca68e1Jean Chalard final int composerSize = composer.size(); 118860a9f85ff7f2753b7e1bed2e00f86de8eca68e1Jean Chalard 119860a9f85ff7f2753b7e1bed2e00f86de8eca68e1Jean Chalard if (composerSize <= 1 || !composer.isBatchMode()) { 120860a9f85ff7f2753b7e1bed2e00f86de8eca68e1Jean Chalard if (composerSize > MAX_WORD_LENGTH - 1) return null; 121860a9f85ff7f2753b7e1bed2e00f86de8eca68e1Jean Chalard for (int i = 0; i < composerSize; i++) { 122860a9f85ff7f2753b7e1bed2e00f86de8eca68e1Jean Chalard mInputCodes[i] = composer.getCodeAt(i); 123860a9f85ff7f2753b7e1bed2e00f86de8eca68e1Jean Chalard } 124860a9f85ff7f2753b7e1bed2e00f86de8eca68e1Jean Chalard } 125860a9f85ff7f2753b7e1bed2e00f86de8eca68e1Jean Chalard 1268eaeb60e7fe930b810dbf5826c40dedf3d328e44Jean Chalard final int count; 127b30d2185f24e3d531f5d46249e7c97391705e469Jean Chalard if (composer.size() <= 1) { 1288eaeb60e7fe930b810dbf5826c40dedf3d328e44Jean Chalard count = TextUtils.isEmpty(prevWord) ? -1 : getBigramsInternal(composer, 129ea98e026f1ad7732279aec6d06107f46ea0af93dJean Chalard prevWordCodePointArray); 130b30d2185f24e3d531f5d46249e7c97391705e469Jean Chalard } else { 1318eaeb60e7fe930b810dbf5826c40dedf3d328e44Jean Chalard count = getWordsInternal(composer, prevWordCodePointArray, proximityInfo); 132b30d2185f24e3d531f5d46249e7c97391705e469Jean Chalard } 133bda7eaa63aace64f3d40eae3affaf281591ffa66Jean Chalard final ArrayList<SuggestedWordInfo> suggestions = new ArrayList<SuggestedWordInfo>(); 134f5cded1c6cf0f39df13750d4f9f5ba66c1b32964satok for (int j = 0; j < count; ++j) { 1358eaeb60e7fe930b810dbf5826c40dedf3d328e44Jean Chalard if (composer.size() > 0 && mOutputScores[j] < 1) break; 136f5cded1c6cf0f39df13750d4f9f5ba66c1b32964satok final int start = j * MAX_WORD_LENGTH; 137979f8690967ff5409fe18f5085858ccdb8e0ccf1satok int len = 0; 1386f233f7ba1ee924844154515dda208bb9b34acb5Jean Chalard while (len < MAX_WORD_LENGTH && mOutputChars[start + len] != 0) { 139f5cded1c6cf0f39df13750d4f9f5ba66c1b32964satok ++len; 140979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 141979f8690967ff5409fe18f5085858ccdb8e0ccf1satok if (len > 0) { 142bda7eaa63aace64f3d40eae3affaf281591ffa66Jean Chalard suggestions.add(new SuggestedWordInfo( 1436f233f7ba1ee924844154515dda208bb9b34acb5Jean Chalard new String(mOutputChars, start, len), 1446f233f7ba1ee924844154515dda208bb9b34acb5Jean Chalard mOutputScores[j], SuggestedWordInfo.KIND_CORRECTION, mDictType)); 145979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 146979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 147d82898c5a91f8aa69d5dc594b7a9290b8be1247aJean Chalard return suggestions; 148923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 149923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 150f5943153ad2ba611feec916119dca2343a1ef6deJean Chalard // TODO: move to native code 1518eaeb60e7fe930b810dbf5826c40dedf3d328e44Jean Chalard private int getBigramsInternal(final WordComposer codes, 1528eaeb60e7fe930b810dbf5826c40dedf3d328e44Jean Chalard final int[] previousWord) { 1538eaeb60e7fe930b810dbf5826c40dedf3d328e44Jean Chalard int codesSize = codes.size(); 1548eaeb60e7fe930b810dbf5826c40dedf3d328e44Jean Chalard 1558eaeb60e7fe930b810dbf5826c40dedf3d328e44Jean Chalard int count = getBigramsNative(mNativeDict, previousWord, previousWord.length, mInputCodes, 1568eaeb60e7fe930b810dbf5826c40dedf3d328e44Jean Chalard codesSize, mOutputChars, mOutputScores, MAX_WORD_LENGTH, MAX_BIGRAMS); 1578eaeb60e7fe930b810dbf5826c40dedf3d328e44Jean Chalard if (count > MAX_BIGRAMS) { 1588eaeb60e7fe930b810dbf5826c40dedf3d328e44Jean Chalard count = MAX_BIGRAMS; 1598eaeb60e7fe930b810dbf5826c40dedf3d328e44Jean Chalard } 1608eaeb60e7fe930b810dbf5826c40dedf3d328e44Jean Chalard return count; 1618eaeb60e7fe930b810dbf5826c40dedf3d328e44Jean Chalard } 1628eaeb60e7fe930b810dbf5826c40dedf3d328e44Jean Chalard 1638eaeb60e7fe930b810dbf5826c40dedf3d328e44Jean Chalard // TODO: move to native code 164ac27e4544b5b5ff7b4f365a4bde5c288d511ae13Jean Chalard // proximityInfo and/or prevWordForBigrams may not be null. 1658eaeb60e7fe930b810dbf5826c40dedf3d328e44Jean Chalard private int getWordsInternal(final WordComposer codes, 166ea98e026f1ad7732279aec6d06107f46ea0af93dJean Chalard final int[] prevWord, final ProximityInfo proximityInfo) { 167e77f2996ea4eca42fbb46d0ce0a6055233b21c38Jean Chalard final InputPointers ips = codes.getInputPointers(); 168e77f2996ea4eca42fbb46d0ce0a6055233b21c38Jean Chalard final boolean isGesture = codes.isBatchMode(); 169e77f2996ea4eca42fbb46d0ce0a6055233b21c38Jean Chalard final int codesSize; 170e77f2996ea4eca42fbb46d0ce0a6055233b21c38Jean Chalard if (isGesture) { 171e77f2996ea4eca42fbb46d0ce0a6055233b21c38Jean Chalard codesSize = ips.getPointerSize(); 172e77f2996ea4eca42fbb46d0ce0a6055233b21c38Jean Chalard } else { 173e77f2996ea4eca42fbb46d0ce0a6055233b21c38Jean Chalard codesSize = codes.size(); 174e77f2996ea4eca42fbb46d0ce0a6055233b21c38Jean Chalard } 175e77f2996ea4eca42fbb46d0ce0a6055233b21c38Jean Chalard 1768eaeb60e7fe930b810dbf5826c40dedf3d328e44Jean Chalard return getSuggestionsNative(mNativeDict, proximityInfo.getNativeProximityInfo(), 177e77f2996ea4eca42fbb46d0ce0a6055233b21c38Jean Chalard ips.getXCoordinates(), ips.getYCoordinates(), ips.getTimes(), ips.getPointerIds(), 178e77f2996ea4eca42fbb46d0ce0a6055233b21c38Jean Chalard mInputCodes, codesSize, 0 /* unused */, isGesture, prevWord, 179e77f2996ea4eca42fbb46d0ce0a6055233b21c38Jean Chalard mUseFullEditDistance, mOutputChars, mOutputScores, mSpaceIndices); 1806f4eba814a7f8426617db61f928a965209ebf359Tadashi G. Takaoka } 1816f4eba814a7f8426617db61f928a965209ebf359Tadashi G. Takaoka 1826f4eba814a7f8426617db61f928a965209ebf359Tadashi G. Takaoka /* package for test */ boolean isValidDictionary() { 1836f4eba814a7f8426617db61f928a965209ebf359Tadashi G. Takaoka return mNativeDict != 0; 1846f4eba814a7f8426617db61f928a965209ebf359Tadashi G. Takaoka } 1856f4eba814a7f8426617db61f928a965209ebf359Tadashi G. Takaoka 1860028ed3627ff4f37a62a80f3b2c857e373cd5090satok public static float calcNormalizedScore(String before, String after, int score) { 187be0cf72253f15bff6abdeaa79f60a56f06ab7b86satok return calcNormalizedScoreNative(before.toCharArray(), before.length(), 188be0cf72253f15bff6abdeaa79f60a56f06ab7b86satok after.toCharArray(), after.length(), score); 189be0cf72253f15bff6abdeaa79f60a56f06ab7b86satok } 190be0cf72253f15bff6abdeaa79f60a56f06ab7b86satok 191be0cf72253f15bff6abdeaa79f60a56f06ab7b86satok public static int editDistance(String before, String after) { 192be0cf72253f15bff6abdeaa79f60a56f06ab7b86satok return editDistanceNative( 193be0cf72253f15bff6abdeaa79f60a56f06ab7b86satok before.toCharArray(), before.length(), after.toCharArray(), after.length()); 194be0cf72253f15bff6abdeaa79f60a56f06ab7b86satok } 195be0cf72253f15bff6abdeaa79f60a56f06ab7b86satok 196923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project @Override 197923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public boolean isValidWord(CharSequence word) { 198c88f61215c5b9ca6e0cc3f776e3b7da19eec9caeSatoshi Kataoka return getFrequency(word) >= 0; 199c88f61215c5b9ca6e0cc3f776e3b7da19eec9caeSatoshi Kataoka } 200c88f61215c5b9ca6e0cc3f776e3b7da19eec9caeSatoshi Kataoka 201c88f61215c5b9ca6e0cc3f776e3b7da19eec9caeSatoshi Kataoka @Override 202c88f61215c5b9ca6e0cc3f776e3b7da19eec9caeSatoshi Kataoka public int getFrequency(CharSequence word) { 203c88f61215c5b9ca6e0cc3f776e3b7da19eec9caeSatoshi Kataoka if (word == null) return -1; 204522a04ea5b249d0af556647d2abcad57e5b99b4fJean Chalard int[] chars = StringUtils.toCodePointArray(word.toString()); 205c88f61215c5b9ca6e0cc3f776e3b7da19eec9caeSatoshi Kataoka return getFrequencyNative(mNativeDict, chars, chars.length); 206923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 207c3df2d6fd27f3a5b84040b59aece3367769f0cb6Amith Yamasani 2084d289d39aeae21064f63d958974816ceee3e9fdeTom Ouyang // TODO: Add a batch process version (isValidBigramMultiple?) to avoid excessive numbers of jni 2094d289d39aeae21064f63d958974816ceee3e9fdeTom Ouyang // calls when checking for changes in an entire dictionary. 2104d289d39aeae21064f63d958974816ceee3e9fdeTom Ouyang public boolean isValidBigram(CharSequence word1, CharSequence word2) { 2114d289d39aeae21064f63d958974816ceee3e9fdeTom Ouyang if (TextUtils.isEmpty(word1) || TextUtils.isEmpty(word2)) return false; 2124d289d39aeae21064f63d958974816ceee3e9fdeTom Ouyang int[] chars1 = StringUtils.toCodePointArray(word1.toString()); 2134d289d39aeae21064f63d958974816ceee3e9fdeTom Ouyang int[] chars2 = StringUtils.toCodePointArray(word2.toString()); 2144d289d39aeae21064f63d958974816ceee3e9fdeTom Ouyang return isValidBigramNative(mNativeDict, chars1, chars2); 2154d289d39aeae21064f63d958974816ceee3e9fdeTom Ouyang } 2164d289d39aeae21064f63d958974816ceee3e9fdeTom Ouyang 21736fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani @Override 218923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public synchronized void close() { 219da50e1e98dadc3733c615dfb8d87fe8b4688c782Ken Wakasa closeInternal(); 220da50e1e98dadc3733c615dfb8d87fe8b4688c782Ken Wakasa } 221da50e1e98dadc3733c615dfb8d87fe8b4688c782Ken Wakasa 222da50e1e98dadc3733c615dfb8d87fe8b4688c782Ken Wakasa private void closeInternal() { 223923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project if (mNativeDict != 0) { 224923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project closeNative(mNativeDict); 225923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project mNativeDict = 0; 226923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 227923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 228923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 229923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project @Override 230923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project protected void finalize() throws Throwable { 231da50e1e98dadc3733c615dfb8d87fe8b4688c782Ken Wakasa try { 232da50e1e98dadc3733c615dfb8d87fe8b4688c782Ken Wakasa closeInternal(); 233da50e1e98dadc3733c615dfb8d87fe8b4688c782Ken Wakasa } finally { 234da50e1e98dadc3733c615dfb8d87fe8b4688c782Ken Wakasa super.finalize(); 235da50e1e98dadc3733c615dfb8d87fe8b4688c782Ken Wakasa } 236923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 237923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project} 238