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