Use the whitelist as a dictionary in the spell checker.

Bug: 5402436
Change-Id: If89b8bbdebf6751697c4788270d01d4639cff665
diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java
index f6f5581..caa5aac 100644
--- a/java/src/com/android/inputmethod/latin/Suggest.java
+++ b/java/src/com/android/inputmethod/latin/Suggest.java
@@ -67,10 +67,10 @@
     public static final int DIC_USER_UNIGRAM = 3;
     public static final int DIC_CONTACTS = 4;
     public static final int DIC_USER_BIGRAM = 5;
+    public static final int DIC_WHITELIST = 6;
     // If you add a type of dictionary, increment DIC_TYPE_LAST_ID
     // TODO: this value seems unused. Remove it?
-    public static final int DIC_TYPE_LAST_ID = 5;
-
+    public static final int DIC_TYPE_LAST_ID = 6;
     public static final String DICT_KEY_MAIN = "main";
     public static final String DICT_KEY_CONTACTS = "contacts";
     // User dictionary, the system-managed one.
@@ -360,7 +360,7 @@
         final String typedWordString = typedWord == null ? null : typedWord.toString();
 
         CharSequence whitelistedWord = capitalizeWord(mIsAllUpperCase, mIsFirstCharCapitalized,
-                mWhiteListDictionary.getWhiteListedWord(typedWordString));
+                mWhiteListDictionary.getWhitelistedWord(typedWordString));
 
         mAutoCorrection.updateAutoCorrectionStatus(mUnigramDictionaries, wordComposer,
                 mSuggestions, mScores, typedWord, mAutoCorrectionThreshold, mCorrectionMode,
diff --git a/java/src/com/android/inputmethod/latin/WhitelistDictionary.java b/java/src/com/android/inputmethod/latin/WhitelistDictionary.java
index 96241a3..8f349ce 100644
--- a/java/src/com/android/inputmethod/latin/WhitelistDictionary.java
+++ b/java/src/com/android/inputmethod/latin/WhitelistDictionary.java
@@ -27,7 +27,7 @@
 import java.util.HashMap;
 import java.util.Locale;
 
-public class WhitelistDictionary extends Dictionary {
+public class WhitelistDictionary extends ExpandableDictionary {
 
     private static final boolean DBG = LatinImeLogger.sDBG;
     private static final String TAG = WhitelistDictionary.class.getSimpleName();
@@ -35,7 +35,9 @@
     private final HashMap<String, Pair<Integer, String>> mWhitelistWords =
             new HashMap<String, Pair<Integer, String>>();
 
+    // TODO: Conform to the async load contact of ExpandableDictionary
     public WhitelistDictionary(final Context context, final Locale locale) {
+        super(context, Suggest.DIC_WHITELIST);
         final Resources res = context.getResources();
         final Locale previousLocale = LocaleUtils.setSystemLocale(res, locale);
         if (context != null) {
@@ -61,6 +63,7 @@
                 if (before != null && after != null) {
                     mWhitelistWords.put(
                             before.toLowerCase(), new Pair<Integer, String>(score, after));
+                    addWord(after, score);
                 }
             }
         } catch (NumberFormatException e) {
@@ -70,30 +73,18 @@
         }
     }
 
-    public String getWhiteListedWord(String before) {
+    public String getWhitelistedWord(String before) {
         if (before == null) return null;
         final String lowerCaseBefore = before.toLowerCase();
         if(mWhitelistWords.containsKey(lowerCaseBefore)) {
             if (DBG) {
-                Log.d(TAG, "--- found whiteListedWord: " + lowerCaseBefore);
+                Log.d(TAG, "--- found whitelistedWord: " + lowerCaseBefore);
             }
             return mWhitelistWords.get(lowerCaseBefore).second;
         }
         return null;
     }
 
-    // Not used for WhitelistDictionary.  We use getWhitelistedWord() in Suggest.java instead
-    @Override
-    public void getWords(final WordComposer composer, final WordCallback callback,
-            final ProximityInfo proximityInfo) {
-    }
-
-    @Override
-    public boolean isValidWord(CharSequence word) {
-        if (TextUtils.isEmpty(word)) return false;
-        return !TextUtils.isEmpty(getWhiteListedWord(word.toString()));
-    }
-
     // See LatinIME#updateSuggestions. This breaks in the (queer) case that the whitelist
     // lists that word a should autocorrect to word b, and word c would autocorrect to
     // an upper-cased version of a. In this case, the way this return value is used would
@@ -105,8 +96,11 @@
     // ever be - it doesn't make sense. But still.
     public boolean shouldForciblyAutoCorrectFrom(CharSequence word) {
         if (TextUtils.isEmpty(word)) return false;
-        final String correction = getWhiteListedWord(word.toString());
+        final String correction = getWhitelistedWord(word.toString());
         if (TextUtils.isEmpty(correction)) return false;
         return !correction.equals(word);
     }
+
+    // Leave implementation of getWords and isValidWord to the superclass.
+    // The words have been added to the ExpandableDictionary with addWord() inside initWordlist.
 }
diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
index 4d569b8..f9e6a5e 100644
--- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
+++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
@@ -37,6 +37,7 @@
 import com.android.inputmethod.latin.R;
 import com.android.inputmethod.latin.SynchronouslyLoadedUserDictionary;
 import com.android.inputmethod.latin.Utils;
+import com.android.inputmethod.latin.WhitelistDictionary;
 import com.android.inputmethod.latin.WordComposer;
 
 import java.util.ArrayList;
@@ -79,6 +80,8 @@
             Collections.synchronizedMap(new TreeMap<String, DictionaryPool>());
     private Map<String, Dictionary> mUserDictionaries =
             Collections.synchronizedMap(new TreeMap<String, Dictionary>());
+    private Map<String, Dictionary> mWhitelistDictionaries =
+            Collections.synchronizedMap(new TreeMap<String, Dictionary>());
 
     // The threshold for a candidate to be offered as a suggestion.
     private double mSuggestionThreshold;
@@ -253,12 +256,17 @@
         mDictionaryPools = Collections.synchronizedMap(new TreeMap<String, DictionaryPool>());
         final Map<String, Dictionary> oldUserDictionaries = mUserDictionaries;
         mUserDictionaries = Collections.synchronizedMap(new TreeMap<String, Dictionary>());
+        final Map<String, Dictionary> oldWhitelistDictionaries = mWhitelistDictionaries;
+        mWhitelistDictionaries = Collections.synchronizedMap(new TreeMap<String, Dictionary>());
         for (DictionaryPool pool : oldPools.values()) {
             pool.close();
         }
         for (Dictionary dict : oldUserDictionaries.values()) {
             dict.close();
         }
+        for (Dictionary dict : oldWhitelistDictionaries.values()) {
+            dict.close();
+        }
         return false;
     }
 
@@ -280,12 +288,18 @@
                 DictionaryFactory.createDictionaryFromManager(this, locale, fallbackResourceId,
                         USE_FULL_EDIT_DISTANCE_FLAG_ARRAY);
         final String localeStr = locale.toString();
-        Dictionary userDict = mUserDictionaries.get(localeStr);
-        if (null == userDict) {
-            userDict = new SynchronouslyLoadedUserDictionary(this, localeStr, true);
-            mUserDictionaries.put(localeStr, userDict);
+        Dictionary userDictionary = mUserDictionaries.get(localeStr);
+        if (null == userDictionary) {
+            userDictionary = new SynchronouslyLoadedUserDictionary(this, localeStr, true);
+            mUserDictionaries.put(localeStr, userDictionary);
         }
-        dictionaryCollection.addDictionary(userDict);
+        dictionaryCollection.addDictionary(userDictionary);
+        Dictionary whitelistDictionary = mWhitelistDictionaries.get(localeStr);
+        if (null == whitelistDictionary) {
+            whitelistDictionary = new WhitelistDictionary(this, locale);
+            mWhitelistDictionaries.put(localeStr, whitelistDictionary);
+        }
+        dictionaryCollection.addDictionary(whitelistDictionary);
         return new DictAndProximity(dictionaryCollection, proximityInfo);
     }