187a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi/*
287a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi * Copyright (C) 2013 The Android Open Source Project
387a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi *
487a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi * Licensed under the Apache License, Version 2.0 (the "License");
587a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi * you may not use this file except in compliance with the License.
687a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi * You may obtain a copy of the License at
787a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi *
887a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi *      http://www.apache.org/licenses/LICENSE-2.0
987a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi *
1087a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi * Unless required by applicable law or agreed to in writing, software
1187a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi * distributed under the License is distributed on an "AS IS" BASIS,
1287a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1387a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi * See the License for the specific language governing permissions and
1487a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi * limitations under the License.
1587a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi */
1687a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi
1787a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagipackage com.android.inputmethod.latin.personalization;
1887a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi
1987a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagiimport android.content.Context;
2087a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi
21e5a35711b854aedeeea2f45105b941b9deee49bcSatoshi Kataokaimport com.android.inputmethod.annotations.UsedForTesting;
2297485273d7c5fdf9b05a7a1c1397cce9721a62d0Satoshi Kataokaimport com.android.inputmethod.compat.ActivityManagerCompatUtils;
2387a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagiimport com.android.inputmethod.keyboard.ProximityInfo;
2487a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagiimport com.android.inputmethod.latin.AbstractDictionaryWriter;
2587a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagiimport com.android.inputmethod.latin.ExpandableDictionary;
2687a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagiimport com.android.inputmethod.latin.WordComposer;
2787a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagiimport com.android.inputmethod.latin.ExpandableDictionary.NextWord;
2887a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagiimport com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
2987a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagiimport com.android.inputmethod.latin.makedict.DictEncoder;
3087a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagiimport com.android.inputmethod.latin.makedict.FormatSpec;
3187a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagiimport com.android.inputmethod.latin.makedict.UnsupportedFormatException;
3287a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagiimport com.android.inputmethod.latin.utils.UserHistoryDictIOUtils;
3387a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagiimport com.android.inputmethod.latin.utils.UserHistoryDictIOUtils.BigramDictionaryInterface;
3487a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagiimport com.android.inputmethod.latin.utils.UserHistoryForgettingCurveUtils;
3587a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagiimport com.android.inputmethod.latin.utils.UserHistoryForgettingCurveUtils.ForgettingCurveParams;
3687a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi
3787a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagiimport java.io.IOException;
3887a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagiimport java.util.ArrayList;
395ed30a7660048ef4bf78077e77554c97786eae2bKeisuke Kuroyanagiimport java.util.Map;
4087a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi
4187a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi// Currently this class is used to implement dynamic prodiction dictionary.
4287a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi// TODO: Move to native code.
4387a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagipublic class DynamicPersonalizationDictionaryWriter extends AbstractDictionaryWriter {
4487a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi    private static final String TAG = DynamicPersonalizationDictionaryWriter.class.getSimpleName();
4587a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi    /** Maximum number of pairs. Pruning will start when databases goes above this number. */
4697485273d7c5fdf9b05a7a1c1397cce9721a62d0Satoshi Kataoka    public static final int DEFAULT_MAX_HISTORY_BIGRAMS = 10000;
4797485273d7c5fdf9b05a7a1c1397cce9721a62d0Satoshi Kataoka    public static final int LOW_MEMORY_MAX_HISTORY_BIGRAMS = 2000;
4887a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi
4987a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi    /** Any pair being typed or picked */
5087a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi    private static final int FREQUENCY_FOR_TYPED = 2;
5187a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi
5287a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi    private static final int BINARY_DICT_VERSION = 3;
5387a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi    private static final FormatSpec.FormatOptions FORMAT_OPTIONS =
5487a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi            new FormatSpec.FormatOptions(BINARY_DICT_VERSION, true /* supportsDynamicUpdate */);
5587a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi
5687a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi    private final UserHistoryDictionaryBigramList mBigramList =
5787a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi            new UserHistoryDictionaryBigramList();
5887a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi    private final ExpandableDictionary mExpandableDictionary;
5997485273d7c5fdf9b05a7a1c1397cce9721a62d0Satoshi Kataoka    private final int mMaxHistoryBigrams;
6087a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi
6187a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi    public DynamicPersonalizationDictionaryWriter(final Context context, final String dictType) {
6287a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi        super(context, dictType);
636e04d6593239e841f5dac0d3f32d613967c11e22Keisuke Kuroyanagi        mExpandableDictionary = new ExpandableDictionary(dictType);
6497485273d7c5fdf9b05a7a1c1397cce9721a62d0Satoshi Kataoka        final boolean isLowRamDevice = ActivityManagerCompatUtils.isLowRamDevice(context);
6597485273d7c5fdf9b05a7a1c1397cce9721a62d0Satoshi Kataoka        mMaxHistoryBigrams = isLowRamDevice ?
6697485273d7c5fdf9b05a7a1c1397cce9721a62d0Satoshi Kataoka                LOW_MEMORY_MAX_HISTORY_BIGRAMS : DEFAULT_MAX_HISTORY_BIGRAMS;
6787a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi    }
6887a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi
6987a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi    @Override
7087a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi    public void clear() {
7187a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi        mBigramList.evictAll();
7287a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi        mExpandableDictionary.clearDictionary();
7387a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi    }
7487a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi
7587a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi    /**
7687a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi     * Adds a word unigram to the fusion dictionary. Call updateBinaryDictionary when all changes
7787a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi     * are done to update the binary dictionary.
78f3204eebb19f0f8fae9d6d81e7e2b430f29829a0Jean Chalard     * @param word The word to add.
79f3204eebb19f0f8fae9d6d81e7e2b430f29829a0Jean Chalard     * @param shortcutTarget A shortcut target for this word, or null if none.
80f3204eebb19f0f8fae9d6d81e7e2b430f29829a0Jean Chalard     * @param frequency The frequency for this unigram.
81f3204eebb19f0f8fae9d6d81e7e2b430f29829a0Jean Chalard     * @param shortcutFreq The frequency of the shortcut (0~15, with 15 = whitelist). Ignored
82f3204eebb19f0f8fae9d6d81e7e2b430f29829a0Jean Chalard     *   if shortcutTarget is null.
83f3204eebb19f0f8fae9d6d81e7e2b430f29829a0Jean Chalard     * @param isNotAWord true if this is not a word, i.e. shortcut only.
8487a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi     */
8587a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi    @Override
8687a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi    public void addUnigramWord(final String word, final String shortcutTarget, final int frequency,
87f3204eebb19f0f8fae9d6d81e7e2b430f29829a0Jean Chalard            final int shortcutFreq, final boolean isNotAWord) {
8897485273d7c5fdf9b05a7a1c1397cce9721a62d0Satoshi Kataoka        if (mBigramList.size() > mMaxHistoryBigrams * 2) {
89a328f538c34ad2dafdfa53642085cb1072224d80Yuichiro Hanada            // Too many entries: just stop adding new vocabulary and wait next refresh.
9097485273d7c5fdf9b05a7a1c1397cce9721a62d0Satoshi Kataoka            return;
9197485273d7c5fdf9b05a7a1c1397cce9721a62d0Satoshi Kataoka        }
92f3204eebb19f0f8fae9d6d81e7e2b430f29829a0Jean Chalard        mExpandableDictionary.addWord(word, shortcutTarget, frequency, shortcutFreq);
9387a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi        mBigramList.addBigram(null, word, (byte)frequency);
9487a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi    }
9587a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi
9687a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi    @Override
9787a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi    public void addBigramWords(final String word0, final String word1, final int frequency,
9887a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi            final boolean isValid, final long lastModifiedTime) {
9997485273d7c5fdf9b05a7a1c1397cce9721a62d0Satoshi Kataoka        if (mBigramList.size() > mMaxHistoryBigrams * 2) {
100a328f538c34ad2dafdfa53642085cb1072224d80Yuichiro Hanada            // Too many entries: just stop adding new vocabulary and wait next refresh.
10197485273d7c5fdf9b05a7a1c1397cce9721a62d0Satoshi Kataoka            return;
10297485273d7c5fdf9b05a7a1c1397cce9721a62d0Satoshi Kataoka        }
10387a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi        if (lastModifiedTime > 0) {
10487a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi            mExpandableDictionary.setBigramAndGetFrequency(word0, word1,
10587a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi                    new ForgettingCurveParams(frequency, System.currentTimeMillis(),
10687a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi                            lastModifiedTime));
10787a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi            mBigramList.addBigram(word0, word1, (byte)frequency);
10887a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi        } else {
10987a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi            mExpandableDictionary.setBigramAndGetFrequency(word0, word1,
11087a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi                    new ForgettingCurveParams(isValid));
11187a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi            mBigramList.addBigram(word0, word1, (byte)frequency);
11287a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi        }
11387a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi    }
11487a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi
11587a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi    @Override
11687a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi    public void removeBigramWords(final String word0, final String word1) {
11787a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi        if (mBigramList.removeBigram(word0, word1)) {
11887a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi            mExpandableDictionary.removeBigram(word0, word1);
11987a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi        }
12087a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi    }
12187a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi
12287a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi    @Override
1235ed30a7660048ef4bf78077e77554c97786eae2bKeisuke Kuroyanagi    protected void writeDictionary(final DictEncoder dictEncoder,
1245ed30a7660048ef4bf78077e77554c97786eae2bKeisuke Kuroyanagi            final Map<String, String> attributeMap) throws IOException, UnsupportedFormatException {
12587a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi        UserHistoryDictIOUtils.writeDictionary(dictEncoder,
12697485273d7c5fdf9b05a7a1c1397cce9721a62d0Satoshi Kataoka                new FrequencyProvider(mBigramList, mExpandableDictionary, mMaxHistoryBigrams),
12797485273d7c5fdf9b05a7a1c1397cce9721a62d0Satoshi Kataoka                mBigramList, FORMAT_OPTIONS);
12887a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi    }
12987a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi
13087a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi    private static class FrequencyProvider implements BigramDictionaryInterface {
13197485273d7c5fdf9b05a7a1c1397cce9721a62d0Satoshi Kataoka        private final UserHistoryDictionaryBigramList mBigramList;
13297485273d7c5fdf9b05a7a1c1397cce9721a62d0Satoshi Kataoka        private final ExpandableDictionary mExpandableDictionary;
13397485273d7c5fdf9b05a7a1c1397cce9721a62d0Satoshi Kataoka        private final int mMaxHistoryBigrams;
13487a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi
13587a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi        public FrequencyProvider(final UserHistoryDictionaryBigramList bigramList,
13697485273d7c5fdf9b05a7a1c1397cce9721a62d0Satoshi Kataoka                final ExpandableDictionary expandableDictionary, final int maxHistoryBigrams) {
13787a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi            mBigramList = bigramList;
13887a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi            mExpandableDictionary = expandableDictionary;
13997485273d7c5fdf9b05a7a1c1397cce9721a62d0Satoshi Kataoka            mMaxHistoryBigrams = maxHistoryBigrams;
14087a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi        }
14197485273d7c5fdf9b05a7a1c1397cce9721a62d0Satoshi Kataoka
14287a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi        @Override
14387a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi        public int getFrequency(final String word0, final String word1) {
14487a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi            final int freq;
14587a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi            if (word0 == null) { // unigram
14687a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi                freq = FREQUENCY_FOR_TYPED;
14787a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi            } else { // bigram
14887a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi                final NextWord nw = mExpandableDictionary.getBigramWord(word0, word1);
14987a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi                if (nw != null) {
15087a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi                    final ForgettingCurveParams forgettingCurveParams = nw.getFcParams();
15187a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi                    final byte prevFc = mBigramList.getBigrams(word0).get(word1);
15287a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi                    final byte fc = forgettingCurveParams.getFc();
15387a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi                    final boolean isValid = forgettingCurveParams.isValid();
15487a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi                    if (prevFc > 0 && prevFc == fc) {
15587a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi                        freq = fc & 0xFF;
15687a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi                    } else if (UserHistoryForgettingCurveUtils.
15797485273d7c5fdf9b05a7a1c1397cce9721a62d0Satoshi Kataoka                            needsToSave(fc, isValid, mBigramList.size() <= mMaxHistoryBigrams)) {
15887a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi                        freq = fc & 0xFF;
15987a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi                    } else {
16087a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi                        // Delete this entry
16187a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi                        freq = -1;
16287a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi                    }
16387a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi                } else {
16487a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi                    // Delete this entry
16587a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi                    freq = -1;
16687a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi                }
16787a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi            }
16887a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi            return freq;
16987a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi        }
17087a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi    }
17187a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi
17287a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi    @Override
17387a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi    public ArrayList<SuggestedWordInfo> getSuggestions(final WordComposer composer,
17487a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi            final String prevWord, final ProximityInfo proximityInfo,
175fe87f5f41744a633a2ed91af9b171bda2637649eKeisuke Kuroyanagi            boolean blockOffensiveWords, final int[] additionalFeaturesOptions) {
17687a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi        return mExpandableDictionary.getSuggestions(composer, prevWord, proximityInfo,
177fe87f5f41744a633a2ed91af9b171bda2637649eKeisuke Kuroyanagi                blockOffensiveWords, additionalFeaturesOptions);
17887a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi    }
17987a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi
18087a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi    @Override
18187a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi    public boolean isValidWord(final String word) {
18287a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi        return mExpandableDictionary.isValidWord(word);
18387a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi    }
184e5a35711b854aedeeea2f45105b941b9deee49bcSatoshi Kataoka
185e5a35711b854aedeeea2f45105b941b9deee49bcSatoshi Kataoka    @UsedForTesting
186a328f538c34ad2dafdfa53642085cb1072224d80Yuichiro Hanada    public boolean isInBigramListForTests(final String word) {
187e5a35711b854aedeeea2f45105b941b9deee49bcSatoshi Kataoka        // TODO: Use native method to determine whether the word is in dictionary or not
188a328f538c34ad2dafdfa53642085cb1072224d80Yuichiro Hanada        return mBigramList.containsKey(word) || mBigramList.getBigrams(null).containsKey(word);
189e5a35711b854aedeeea2f45105b941b9deee49bcSatoshi Kataoka    }
19087a72f50c23a4ef357ae623eabc2af16d02466aeKeisuke Kuroyanagi}
191