From f019d505d7da97c03c321eef02c4879c4e0448f6 Mon Sep 17 00:00:00 2001
From: Jean Chalard <jchalard@google.com>
Date: Mon, 29 Aug 2011 18:09:00 +0900
Subject: [PATCH] Fix a bug with synchronicity of spell checking/user dict

This fixes a race condition that would end up with the spell
checker not finding some words in the user dictionary when it
just booted.

Bug: 5194627
Change-Id: I1ba911cc53e6ae3b111d54a6f91d1d5feef3f5de
---
 .../latin/ExpandableDictionary.java           | 14 +++++--
 .../SynchronouslyLoadedUserDictionary.java    | 41 +++++++++++++++++++
 .../AndroidSpellCheckerService.java           |  3 +-
 3 files changed, 54 insertions(+), 4 deletions(-)
 create mode 100644 java/src/com/android/inputmethod/latin/SynchronouslyLoadedUserDictionary.java

diff --git a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java
index 9f4777f5ab..2b78b9065e 100644
--- a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java
+++ b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java
@@ -202,7 +202,11 @@ public class ExpandableDictionary extends Dictionary {
             // Currently updating contacts, don't return any results.
             if (mUpdatingDictionary) return;
         }
+        getWordsInner(codes, callback, proximityInfo);
+    }
 
+    protected final void getWordsInner(final WordComposer codes, final WordCallback callback,
+            final ProximityInfo proximityInfo) {
         mInputLength = codes.size();
         if (mCodes.length < mInputLength) mCodes = new int[mInputLength][];
         // Cache the codes so that we don't have to lookup an array list
@@ -223,8 +227,7 @@ public class ExpandableDictionary extends Dictionary {
             if (mRequiresReload) startDictionaryLoadingTaskLocked();
             if (mUpdatingDictionary) return false;
         }
-        final int freq = getWordFrequency(word);
-        return freq > -1;
+        return getWordFrequency(word) > -1;
     }
 
     /**
@@ -464,7 +467,7 @@ public class ExpandableDictionary extends Dictionary {
     }
 
     /**
-     * Used only for testing purposes
+     * Used for testing purposes and in the spell checker
      * This function will wait for loading from database to be done
      */
     void waitForDictionaryLoading() {
@@ -477,6 +480,11 @@ public class ExpandableDictionary extends Dictionary {
         }
     }
 
+    protected final void blockingReloadDictionaryIfRequired() {
+        reloadDictionaryIfRequired();
+        waitForDictionaryLoading();
+    }
+
     // Local to reverseLookUp, but do not allocate each time.
     private final char[] mLookedUpString = new char[MAX_WORD_LENGTH];
 
diff --git a/java/src/com/android/inputmethod/latin/SynchronouslyLoadedUserDictionary.java b/java/src/com/android/inputmethod/latin/SynchronouslyLoadedUserDictionary.java
new file mode 100644
index 0000000000..4a812b3a93
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/SynchronouslyLoadedUserDictionary.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.latin;
+
+import android.content.Context;
+
+import com.android.inputmethod.keyboard.ProximityInfo;
+
+public class SynchronouslyLoadedUserDictionary extends UserDictionary {
+
+    public SynchronouslyLoadedUserDictionary(final Context context, final String locale) {
+        super(context, locale);
+    }
+
+    @Override
+    public void getWords(final WordComposer codes, final WordCallback callback,
+            final ProximityInfo proximityInfo) {
+        blockingReloadDictionaryIfRequired();
+        getWordsInner(codes, callback, proximityInfo);
+    }
+
+    @Override
+    public synchronized boolean isValidWord(CharSequence word) {
+        blockingReloadDictionaryIfRequired();
+        return getWordFrequency(word) > -1;
+    }
+}
diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
index 3244bcc656..a6a5b6dd66 100644
--- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
+++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
@@ -34,6 +34,7 @@ import com.android.inputmethod.latin.Dictionary.WordCallback;
 import com.android.inputmethod.latin.DictionaryCollection;
 import com.android.inputmethod.latin.DictionaryFactory;
 import com.android.inputmethod.latin.LocaleUtils;
+import com.android.inputmethod.latin.SynchronouslyLoadedUserDictionary;
 import com.android.inputmethod.latin.UserDictionary;
 import com.android.inputmethod.latin.Utils;
 import com.android.inputmethod.latin.WordComposer;
@@ -156,7 +157,7 @@ public class AndroidSpellCheckerService extends SpellCheckerService {
         final String localeStr = locale.toString();
         Dictionary userDict = mUserDictionaries.get(localeStr);
         if (null == userDict) {
-            userDict = new UserDictionary(this, localeStr);
+            userDict = new SynchronouslyLoadedUserDictionary(this, localeStr);
             mUserDictionaries.put(localeStr, userDict);
         }
         dictionaryCollection.addDictionary(userDict);
-- 
GitLab