Merge "A couple of cleanups.  Remove unnecessary casts." into jb-mr1-dev
diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java
index 0171dc0..06f5db7 100644
--- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java
+++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java
@@ -193,7 +193,7 @@
             if (shouldFilterOut(inText, mScript)) {
                 DictAndProximity dictInfo = null;
                 try {
-                    dictInfo = mDictionaryPool.takeOrGetNull();
+                    dictInfo = mDictionaryPool.pollWithDefaultTimeout();
                     if (null == dictInfo) {
                         return AndroidSpellCheckerService.getNotInDictEmptySuggestions();
                     }
@@ -236,7 +236,7 @@
             boolean isInDict = true;
             DictAndProximity dictInfo = null;
             try {
-                dictInfo = mDictionaryPool.takeOrGetNull();
+                dictInfo = mDictionaryPool.pollWithDefaultTimeout();
                 if (null == dictInfo) {
                     return AndroidSpellCheckerService.getNotInDictEmptySuggestions();
                 }
diff --git a/java/src/com/android/inputmethod/latin/spellcheck/DictionaryPool.java b/java/src/com/android/inputmethod/latin/spellcheck/DictionaryPool.java
index 8fc632e..83f82fa 100644
--- a/java/src/com/android/inputmethod/latin/spellcheck/DictionaryPool.java
+++ b/java/src/com/android/inputmethod/latin/spellcheck/DictionaryPool.java
@@ -16,14 +16,24 @@
 
 package com.android.inputmethod.latin.spellcheck;
 
+import android.util.Log;
+
 import java.util.Locale;
 import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
 
 /**
  * A blocking queue that creates dictionaries up to a certain limit as necessary.
+ * As a deadlock-detecting device, if waiting for more than TIMEOUT = 3 seconds, we
+ * will clear the queue and generate its contents again. This is transparent for
+ * the client code, but may help with sloppy clients.
  */
 @SuppressWarnings("serial")
 public class DictionaryPool extends LinkedBlockingQueue<DictAndProximity> {
+    private final static String TAG = DictionaryPool.class.getSimpleName();
+    // How many seconds we wait for a dictionary to become available. Past this delay, we give up in
+    // fear some bug caused a deadlock, and reset the whole pool.
+    private final static int TIMEOUT = 3;
     private final AndroidSpellCheckerService mService;
     private final int mMaxSize;
     private final Locale mLocale;
@@ -41,13 +51,23 @@
     }
 
     @Override
-    public DictAndProximity take() throws InterruptedException {
+    public DictAndProximity poll(final long timeout, final TimeUnit unit)
+            throws InterruptedException {
         final DictAndProximity dict = poll();
         if (null != dict) return dict;
         synchronized(this) {
             if (mSize >= mMaxSize) {
-                // Our pool is already full. Wait until some dictionary is ready.
-                return super.take();
+                // Our pool is already full. Wait until some dictionary is ready, or TIMEOUT
+                // expires to avoid a deadlock.
+                final DictAndProximity result = super.poll(timeout, unit);
+                if (null == result) {
+                    Log.e(TAG, "Deadlock detected ! Resetting dictionary pool");
+                    clear();
+                    mSize = 1;
+                    return mService.createDictAndProximity(mLocale);
+                } else {
+                    return result;
+                }
             } else {
                 ++mSize;
                 return mService.createDictAndProximity(mLocale);
@@ -56,9 +76,9 @@
     }
 
     // Convenience method
-    public DictAndProximity takeOrGetNull() {
+    public DictAndProximity pollWithDefaultTimeout() {
         try {
-            return take();
+            return poll(TIMEOUT, TimeUnit.SECONDS);
         } catch (InterruptedException e) {
             return null;
         }