Home | History | Annotate | Download | only in spellcheck
      1 /*
      2  * Copyright (C) 2011 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.inputmethod.latin.spellcheck;
     18 
     19 import android.util.Log;
     20 
     21 import com.android.inputmethod.keyboard.ProximityInfo;
     22 import com.android.inputmethod.latin.Dictionary;
     23 import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
     24 import com.android.inputmethod.latin.WordComposer;
     25 import com.android.inputmethod.latin.utils.CollectionUtils;
     26 
     27 import java.util.ArrayList;
     28 import java.util.Locale;
     29 import java.util.concurrent.LinkedBlockingQueue;
     30 import java.util.concurrent.TimeUnit;
     31 
     32 /**
     33  * A blocking queue that creates dictionaries up to a certain limit as necessary.
     34  * As a deadlock-detecting device, if waiting for more than TIMEOUT = 3 seconds, we
     35  * will clear the queue and generate its contents again. This is transparent for
     36  * the client code, but may help with sloppy clients.
     37  */
     38 @SuppressWarnings("serial")
     39 public final class DictionaryPool extends LinkedBlockingQueue<DictAndKeyboard> {
     40     private final static String TAG = DictionaryPool.class.getSimpleName();
     41     // How many seconds we wait for a dictionary to become available. Past this delay, we give up in
     42     // fear some bug caused a deadlock, and reset the whole pool.
     43     private final static int TIMEOUT = 3;
     44     private final AndroidSpellCheckerService mService;
     45     private final int mMaxSize;
     46     private final Locale mLocale;
     47     private int mSize;
     48     private volatile boolean mClosed;
     49     final static ArrayList<SuggestedWordInfo> noSuggestions = CollectionUtils.newArrayList();
     50     private final static DictAndKeyboard dummyDict = new DictAndKeyboard(
     51             new Dictionary(Dictionary.TYPE_MAIN) {
     52                 @Override
     53                 public ArrayList<SuggestedWordInfo> getSuggestions(final WordComposer composer,
     54                         final String prevWord, final ProximityInfo proximityInfo,
     55                         final boolean blockOffensiveWords, final int[] additionalFeaturesOptions) {
     56                     return noSuggestions;
     57                 }
     58                 @Override
     59                 public boolean isValidWord(final String word) {
     60                     // This is never called. However if for some strange reason it ever gets
     61                     // called, returning true is less destructive (it will not underline the
     62                     // word in red).
     63                     return true;
     64                 }
     65             }, null);
     66 
     67     static public boolean isAValidDictionary(final DictAndKeyboard dictInfo) {
     68         return null != dictInfo && dummyDict != dictInfo;
     69     }
     70 
     71     public DictionaryPool(final int maxSize, final AndroidSpellCheckerService service,
     72             final Locale locale) {
     73         super();
     74         mMaxSize = maxSize;
     75         mService = service;
     76         mLocale = locale;
     77         mSize = 0;
     78         mClosed = false;
     79     }
     80 
     81     @Override
     82     public DictAndKeyboard poll(final long timeout, final TimeUnit unit)
     83             throws InterruptedException {
     84         final DictAndKeyboard dict = poll();
     85         if (null != dict) return dict;
     86         synchronized(this) {
     87             if (mSize >= mMaxSize) {
     88                 // Our pool is already full. Wait until some dictionary is ready, or TIMEOUT
     89                 // expires to avoid a deadlock.
     90                 final DictAndKeyboard result = super.poll(timeout, unit);
     91                 if (null == result) {
     92                     Log.e(TAG, "Deadlock detected ! Resetting dictionary pool");
     93                     clear();
     94                     mSize = 1;
     95                     return mService.createDictAndKeyboard(mLocale);
     96                 } else {
     97                     return result;
     98                 }
     99             } else {
    100                 ++mSize;
    101                 return mService.createDictAndKeyboard(mLocale);
    102             }
    103         }
    104     }
    105 
    106     // Convenience method
    107     public DictAndKeyboard pollWithDefaultTimeout() {
    108         try {
    109             return poll(TIMEOUT, TimeUnit.SECONDS);
    110         } catch (InterruptedException e) {
    111             return null;
    112         }
    113     }
    114 
    115     public void close() {
    116         synchronized(this) {
    117             mClosed = true;
    118             for (DictAndKeyboard dict : this) {
    119                 dict.mDictionary.close();
    120             }
    121             clear();
    122         }
    123     }
    124 
    125     @Override
    126     public boolean offer(final DictAndKeyboard dict) {
    127         if (mClosed) {
    128             dict.mDictionary.close();
    129             return super.offer(dummyDict);
    130         } else {
    131             return super.offer(dict);
    132         }
    133     }
    134 }
    135