DictionaryPool.java revision 2dbb5957e3c8354fa9bcb1e08c7ce81387b7fe25
19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2011 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
7b13b9bdad2baf6ad1ec2e56b6b7598fa20f55fc4Mathias Agopian *
8b13b9bdad2baf6ad1ec2e56b6b7598fa20f55fc4Mathias Agopian *      http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage com.android.inputmethod.latin.spellcheck;
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.Log;
209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport com.android.inputmethod.keyboard.ProximityInfo;
229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport com.android.inputmethod.latin.CollectionUtils;
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport com.android.inputmethod.latin.Dictionary;
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport com.android.inputmethod.latin.WordComposer;
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.ArrayList;
289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Locale;
299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.concurrent.LinkedBlockingQueue;
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.concurrent.TimeUnit;
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * A blocking queue that creates dictionaries up to a certain limit as necessary.
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * As a deadlock-detecting device, if waiting for more than TIMEOUT = 3 seconds, we
354df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project * will clear the queue and generate its contents again. This is transparent for
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the client code, but may help with sloppy clients.
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project@SuppressWarnings("serial")
394df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Projectpublic final class DictionaryPool extends LinkedBlockingQueue<DictAndProximity> {
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final static String TAG = DictionaryPool.class.getSimpleName();
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // How many seconds we wait for a dictionary to become available. Past this delay, we give up in
429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // fear some bug caused a deadlock, and reset the whole pool.
439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final static int TIMEOUT = 3;
449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final AndroidSpellCheckerService mService;
459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final int mMaxSize;
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final Locale mLocale;
474cb1753ec6e90d7e747880c599dc1c164a568cf3Elliott Hughes    private int mSize;
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private volatile boolean mClosed;
4931a69fdbe1edd8d686043e8ca7d278289f65808eMike Reed    final static ArrayList<SuggestedWordInfo> noSuggestions = CollectionUtils.newArrayList();
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final static DictAndProximity dummyDict = new DictAndProximity(
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            new Dictionary(Dictionary.TYPE_MAIN) {
529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                @Override
534df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project                public ArrayList<SuggestedWordInfo> getSuggestions(final WordComposer composer,
549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        final String prevWord, final ProximityInfo proximityInfo,
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        final boolean blockOffensiveWords) {
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return noSuggestions;
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                @Override
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                public boolean isValidWord(final String word) {
609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // This is never called. However if for some strange reason it ever gets
619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // called, returning true is less destructive (it will not underline the
629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // word in red).
639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return true;
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }, null);
669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
674cb1753ec6e90d7e747880c599dc1c164a568cf3Elliott Hughes    static public boolean isAValidDictionary(final DictAndProximity dictInfo) {
689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return null != dictInfo && dummyDict != dictInfo;
699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public DictionaryPool(final int maxSize, final AndroidSpellCheckerService service,
729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final Locale locale) {
739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        super();
749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mMaxSize = maxSize;
75ddb76c4644756b31be948d70aaa8ee541dd94999Kenny Root        mService = service;
76ddb76c4644756b31be948d70aaa8ee541dd94999Kenny Root        mLocale = locale;
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mSize = 0;
784cb1753ec6e90d7e747880c599dc1c164a568cf3Elliott Hughes        mClosed = false;
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
824cb1753ec6e90d7e747880c599dc1c164a568cf3Elliott Hughes    public DictAndProximity poll(final long timeout, final TimeUnit unit)
839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throws InterruptedException {
849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final DictAndProximity dict = poll();
859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (null != dict) return dict;
869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized(this) {
874cb1753ec6e90d7e747880c599dc1c164a568cf3Elliott Hughes            if (mSize >= mMaxSize) {
889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Our pool is already full. Wait until some dictionary is ready, or TIMEOUT
899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // expires to avoid a deadlock.
904cb1753ec6e90d7e747880c599dc1c164a568cf3Elliott Hughes                final DictAndProximity result = super.poll(timeout, unit);
91ddb76c4644756b31be948d70aaa8ee541dd94999Kenny Root                if (null == result) {
929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    Log.e(TAG, "Deadlock detected ! Resetting dictionary pool");
939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    clear();
94ddb76c4644756b31be948d70aaa8ee541dd94999Kenny Root                    mSize = 1;
959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return mService.createDictAndProximity(mLocale);
969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else {
974cb1753ec6e90d7e747880c599dc1c164a568cf3Elliott Hughes                    return result;
989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                ++mSize;
1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return mService.createDictAndProximity(mLocale);
1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1044cb1753ec6e90d7e747880c599dc1c164a568cf3Elliott Hughes    }
1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Convenience method
1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public DictAndProximity pollWithDefaultTimeout() {
1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
1094cb1753ec6e90d7e747880c599dc1c164a568cf3Elliott Hughes            return poll(TIMEOUT, TimeUnit.SECONDS);
1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (InterruptedException e) {
1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return null;
1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void close() {
1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized(this) {
1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mClosed = true;
1184cb1753ec6e90d7e747880c599dc1c164a568cf3Elliott Hughes            for (DictAndProximity dict : this) {
1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                dict.mDictionary.close();
1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1214cb1753ec6e90d7e747880c599dc1c164a568cf3Elliott Hughes            clear();
1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
1264cb1753ec6e90d7e747880c599dc1c164a568cf3Elliott Hughes    public boolean offer(final DictAndProximity dict) {
1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mClosed) {
1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            dict.mDictionary.close();
1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return super.offer(dummyDict);
1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return super.offer(dict);
1324cb1753ec6e90d7e747880c599dc1c164a568cf3Elliott Hughes        }
133a1db574036c9bc2d397b69f8200594027e1fff16Romain Guy    }
134a1db574036c9bc2d397b69f8200594027e1fff16Romain Guy}
135a1db574036c9bc2d397b69f8200594027e1fff16Romain Guy