Stop reloading contacts when not appropriate.

A recent change had the contacts reloaded every time a new field
is touched. This change not only fixes the problem, but also removes
reloading contacts when changing language, which should make language
switch within LatinIME lighter.

Bug: 5125034
Change-Id: Ia61c4f75a8617113cdce88a2e2c6fdf073146a2d
diff --git a/java/src/com/android/inputmethod/latin/ContactsDictionary.java b/java/src/com/android/inputmethod/latin/ContactsDictionary.java
index 66a0415..8a7dfb8 100644
--- a/java/src/com/android/inputmethod/latin/ContactsDictionary.java
+++ b/java/src/com/android/inputmethod/latin/ContactsDictionary.java
@@ -49,20 +49,28 @@
 
     private long mLastLoadedContacts;
 
-    public ContactsDictionary(Context context, int dicTypeId) {
+    public ContactsDictionary(final Context context, final int dicTypeId) {
         super(context, dicTypeId);
+        registerObserver(context);
+        loadDictionary();
+    }
+
+    private synchronized void registerObserver(final Context context) {
         // Perform a managed query. The Activity will handle closing and requerying the cursor
         // when needed.
+        if (mObserver != null) return;
         ContentResolver cres = context.getContentResolver();
-
         cres.registerContentObserver(
-                Contacts.CONTENT_URI, true,mObserver = new ContentObserver(null) {
+                Contacts.CONTENT_URI, true, mObserver = new ContentObserver(null) {
                     @Override
                     public void onChange(boolean self) {
                         setRequiresReload(true);
                     }
                 });
-        loadDictionary();
+    }
+
+    public void reopen(final Context context) {
+        registerObserver(context);
     }
 
     @Override
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index a588158..d74babf 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -509,7 +509,7 @@
         if (null == mPrefs) mPrefs = PreferenceManager.getDefaultSharedPreferences(this);
         if (null == mSubtypeSwitcher) mSubtypeSwitcher = SubtypeSwitcher.getInstance();
         mSettingsValues = new Settings.Values(mPrefs, this, mSubtypeSwitcher.getInputLocaleStr());
-        resetContactsDictionary();
+        resetContactsDictionary(null == mSuggest ? null : mSuggest.getContactsDictionary());
     }
 
     private void initSuggest() {
@@ -518,8 +518,12 @@
 
         final Resources res = mResources;
         final Locale savedLocale = Utils.setSystemLocale(res, keyboardLocale);
+        final ContactsDictionary oldContactsDictionary;
         if (mSuggest != null) {
+            oldContactsDictionary = mSuggest.getContactsDictionary();
             mSuggest.close();
+        } else {
+            oldContactsDictionary = null;
         }
 
         int mainDicResId = Utils.getMainDictionaryResourceId(res);
@@ -533,7 +537,7 @@
         mSuggest.setUserDictionary(mUserDictionary);
         mIsUserDictionaryAvaliable = mUserDictionary.isEnabled();
 
-        resetContactsDictionary();
+        resetContactsDictionary(oldContactsDictionary);
 
         mUserUnigramDictionary
                 = new UserUnigramDictionary(this, this, localeStr, Suggest.DIC_USER_UNIGRAM);
@@ -548,11 +552,36 @@
         Utils.setSystemLocale(res, savedLocale);
     }
 
-    private void resetContactsDictionary() {
-        if (null == mSuggest) return;
-        ContactsDictionary contactsDictionary = mSettingsValues.mUseContactsDict
-                ? new ContactsDictionary(this, Suggest.DIC_CONTACTS) : null;
-        mSuggest.setContactsDictionary(contactsDictionary);
+    /**
+     * Resets the contacts dictionary in mSuggest according to the user settings.
+     *
+     * This method takes an optional contacts dictionary to use. Since the contacts dictionary
+     * does not depend on the locale, it can be reused across different instances of Suggest.
+     * The dictionary will also be opened or closed as necessary depending on the settings.
+     *
+     * @param oldContactsDictionary an optional dictionary to use, or null
+     */
+    private void resetContactsDictionary(final ContactsDictionary oldContactsDictionary) {
+        final boolean shouldSetDictionary = (null != mSuggest && mSettingsValues.mUseContactsDict);
+
+        final ContactsDictionary dictionaryToUse;
+        if (!shouldSetDictionary) {
+            // Make sure the dictionary is closed. If it is already closed, this is a no-op,
+            // so it's safe to call it anyways.
+            if (null != oldContactsDictionary) oldContactsDictionary.close();
+            dictionaryToUse = null;
+        } else if (null != oldContactsDictionary) {
+            // Make sure the old contacts dictionary is opened. If it is already open, this is a
+            // no-op, so it's safe to call it anyways.
+            oldContactsDictionary.reopen(this);
+            dictionaryToUse = oldContactsDictionary;
+        } else {
+            dictionaryToUse = new ContactsDictionary(this, Suggest.DIC_CONTACTS);
+        }
+
+        if (null != mSuggest) {
+            mSuggest.setContactsDictionary(dictionaryToUse);
+        }
     }
 
     /* package private */ void resetSuggestMainDict() {
diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java
index 36a29e8..a2d66f3 100644
--- a/java/src/com/android/inputmethod/latin/Suggest.java
+++ b/java/src/com/android/inputmethod/latin/Suggest.java
@@ -88,6 +88,7 @@
     private AutoCorrection mAutoCorrection;
 
     private Dictionary mMainDict;
+    private ContactsDictionary mContactsDict;
     private WhitelistDictionary mWhiteListDictionary;
     private final Map<String, Dictionary> mUnigramDictionaries = new HashMap<String, Dictionary>();
     private final Map<String, Dictionary> mBigramDictionaries = new HashMap<String, Dictionary>();
@@ -197,6 +198,10 @@
         return mMainDict != null;
     }
 
+    public ContactsDictionary getContactsDictionary() {
+        return mContactsDict;
+    }
+
     public Map<String, Dictionary> getUnigramDictionaries() {
         return mUnigramDictionaries;
     }
@@ -218,7 +223,8 @@
      * the contacts dictionary by passing null to this method. In this case no contacts dictionary
      * won't be used.
      */
-    public void setContactsDictionary(Dictionary contactsDictionary) {
+    public void setContactsDictionary(ContactsDictionary contactsDictionary) {
+        mContactsDict = contactsDictionary;
         addOrReplaceDictionary(mUnigramDictionaries, DICT_KEY_CONTACTS, contactsDictionary);
         addOrReplaceDictionary(mBigramDictionaries, DICT_KEY_CONTACTS, contactsDictionary);
     }