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