From db5aedb5a5eea5224e5a732b689c97eead2e35f4 Mon Sep 17 00:00:00 2001 From: Jean Chalard <jchalard@google.com> Date: Thu, 10 Nov 2011 08:21:42 +0900 Subject: [PATCH] Add an option to use contacts or not while spell checking Bug: 5447495 Change-Id: Iffb09895676c3dd1a79d1699b0eac865282508d4 --- java/res/values/strings.xml | 8 +- java/res/xml/spell_checker_settings.xml | 6 +- java/res/xml/spellchecker.xml | 3 +- .../latin/DictionaryCollection.java | 22 ++++- .../AndroidSpellCheckerService.java | 96 ++++++++++++++++--- 5 files changed, 112 insertions(+), 23 deletions(-) diff --git a/java/res/values/strings.xml b/java/res/values/strings.xml index e00547a626..8f999215e8 100644 --- a/java/res/values/strings.xml +++ b/java/res/values/strings.xml @@ -31,11 +31,11 @@ <!-- Title for the spell checking service settings screen --> <string name="android_spell_checker_settings">Spell checking settings</string> - <!-- Title for the "use proximity" option for spell checking [CHAR LIMIT=25] --> - <string name="use_proximity_option_title">Use proximity data</string> + <!-- Title for the spell checker option to turn on/off contact names lookup [CHAR LIMIT=25] --> + <string name="use_contacts_for_spellchecking_option_title">Look up contact names</string> - <!-- Description for the "use proximity" option for spell checking [CHAR LIMIT=65] --> - <string name="use_proximity_option_summary">Use a keyboard-like proximity algorithm for spell checking</string> + <!-- Description for the spell checker option to turn on/off contact names lookup. [CHAR LIMIT=65] --> + <string name="use_contacts_for_spellchecking_option_summary">Spell checker uses entries from your contact list</string> <!-- Option to provide vibrate/haptic feedback on keypress --> <string name="vibrate_on_keypress">Vibrate on keypress</string> diff --git a/java/res/xml/spell_checker_settings.xml b/java/res/xml/spell_checker_settings.xml index f402555c95..222b98b6bd 100644 --- a/java/res/xml/spell_checker_settings.xml +++ b/java/res/xml/spell_checker_settings.xml @@ -18,9 +18,9 @@ xmlns:android="http://schemas.android.com/apk/res/android" android:title="@string/android_spell_checker_settings"> <CheckBoxPreference - android:key="use_proximity" - android:title="@string/use_proximity_option_title" - android:summary="@string/use_proximity_option_summary" + android:key="pref_spellcheck_use_contacts" + android:title="@string/use_contacts_for_spellchecking_option_title" + android:summary="@string/use_contacts_for_spellchecking_option_summary" android:persistent="true" android:defaultValue="true" /> </PreferenceScreen> diff --git a/java/res/xml/spellchecker.xml b/java/res/xml/spellchecker.xml index 30fac5b205..d1269d878f 100644 --- a/java/res/xml/spellchecker.xml +++ b/java/res/xml/spellchecker.xml @@ -21,7 +21,8 @@ <!-- for the spell checker --> <spell-checker xmlns:android="http://schemas.android.com/apk/res/android" - android:label="@string/spell_checker_service_name"> + android:label="@string/spell_checker_service_name" + android:settingsActivity="com.android.inputmethod.latin.spellcheck.SpellCheckerSettingsActivity"> <subtype android:label="@string/subtype_generic" android:subtypeLocale="en" diff --git a/java/src/com/android/inputmethod/latin/DictionaryCollection.java b/java/src/com/android/inputmethod/latin/DictionaryCollection.java index 739153044b..c19a5a718a 100644 --- a/java/src/com/android/inputmethod/latin/DictionaryCollection.java +++ b/java/src/com/android/inputmethod/latin/DictionaryCollection.java @@ -18,6 +18,8 @@ package com.android.inputmethod.latin; import com.android.inputmethod.keyboard.ProximityInfo; +import android.util.Log; + import java.util.Collection; import java.util.Collections; import java.util.List; @@ -27,7 +29,7 @@ import java.util.concurrent.CopyOnWriteArrayList; * Class for a collection of dictionaries that behave like one dictionary. */ public class DictionaryCollection extends Dictionary { - + private final String TAG = DictionaryCollection.class.getSimpleName(); protected final List<Dictionary> mDictionaries; public DictionaryCollection() { @@ -75,7 +77,21 @@ public class DictionaryCollection extends Dictionary { dict.close(); } - public void addDictionary(Dictionary newDict) { - if (null != newDict) mDictionaries.add(newDict); + // Warning: this is not thread-safe. Take necessary precaution when calling. + public void addDictionary(final Dictionary newDict) { + if (null == newDict) return; + if (mDictionaries.contains(newDict)) { + Log.w(TAG, "This collection already contains this dictionary: " + newDict); + } + mDictionaries.add(newDict); + } + + // Warning: this is not thread-safe. Take necessary precaution when calling. + public void removeDictionary(final Dictionary dict) { + if (mDictionaries.contains(dict)) { + mDictionaries.remove(dict); + } else { + Log.w(TAG, "This collection does not contain this dictionary: " + dict); + } } } diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java index 93540ab126..9dfbe7a54e 100644 --- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java +++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java @@ -17,7 +17,9 @@ package com.android.inputmethod.latin.spellcheck; import android.content.Intent; +import android.content.SharedPreferences; import android.content.res.Resources; +import android.preference.PreferenceManager; import android.service.textservice.SpellCheckerService; import android.text.TextUtils; import android.util.Log; @@ -41,21 +43,27 @@ import com.android.inputmethod.latin.Utils; import com.android.inputmethod.latin.WhitelistDictionary; import com.android.inputmethod.latin.WordComposer; +import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.Iterator; import java.util.Locale; import java.util.Map; import java.util.TreeMap; +import java.util.HashSet; /** * Service for spell checking, using LatinIME's dictionaries and mechanisms. */ -public class AndroidSpellCheckerService extends SpellCheckerService { +public class AndroidSpellCheckerService extends SpellCheckerService + implements SharedPreferences.OnSharedPreferenceChangeListener { private static final String TAG = AndroidSpellCheckerService.class.getSimpleName(); private static final boolean DBG = false; private static final int POOL_SIZE = 2; + public static final String PREF_USE_CONTACTS_KEY = "pref_spellcheck_use_contacts"; + private static final int CAPITALIZE_NONE = 0; // No caps, or mixed case private static final int CAPITALIZE_FIRST = 1; // First only private static final int CAPITALIZE_ALL = 2; // All caps @@ -84,6 +92,12 @@ public class AndroidSpellCheckerService extends SpellCheckerService { private double mSuggestionThreshold; // The threshold for a suggestion to be considered "recommended". private double mRecommendedThreshold; + // Whether to use the contacts dictionary + private boolean mUseContactsDictionary; + private final Object mUseContactsLock = new Object(); + + private final HashSet<WeakReference<DictionaryCollection>> mDictionaryCollectionsList = + new HashSet<WeakReference<DictionaryCollection>>(); @Override public void onCreate() { super.onCreate(); @@ -91,6 +105,57 @@ public class AndroidSpellCheckerService extends SpellCheckerService { Double.parseDouble(getString(R.string.spellchecker_suggestion_threshold_value)); mRecommendedThreshold = Double.parseDouble(getString(R.string.spellchecker_recommended_threshold_value)); + final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); + prefs.registerOnSharedPreferenceChangeListener(this); + onSharedPreferenceChanged(prefs, PREF_USE_CONTACTS_KEY); + } + + @Override + public void onSharedPreferenceChanged(final SharedPreferences prefs, final String key) { + if (!PREF_USE_CONTACTS_KEY.equals(key)) return; + synchronized(mUseContactsLock) { + mUseContactsDictionary = prefs.getBoolean(PREF_USE_CONTACTS_KEY, true); + if (mUseContactsDictionary) { + startUsingContactsDictionaryLocked(); + } else { + stopUsingContactsDictionaryLocked(); + } + } + } + + private void startUsingContactsDictionaryLocked() { + if (null == mContactsDictionary) { + mContactsDictionary = new SynchronouslyLoadedContactsDictionary(this); + } + final Iterator<WeakReference<DictionaryCollection>> iterator = + mDictionaryCollectionsList.iterator(); + while (iterator.hasNext()) { + final WeakReference<DictionaryCollection> dictRef = iterator.next(); + final DictionaryCollection dict = dictRef.get(); + if (null == dict) { + iterator.remove(); + } else { + dict.addDictionary(mContactsDictionary); + } + } + } + + private void stopUsingContactsDictionaryLocked() { + if (null == mContactsDictionary) return; + final SynchronouslyLoadedContactsDictionary contactsDict = mContactsDictionary; + mContactsDictionary = null; + final Iterator<WeakReference<DictionaryCollection>> iterator = + mDictionaryCollectionsList.iterator(); + while (iterator.hasNext()) { + final WeakReference<DictionaryCollection> dictRef = iterator.next(); + final DictionaryCollection dict = dictRef.get(); + if (null == dict) { + iterator.remove(); + } else { + dict.removeDictionary(contactsDict); + } + } + contactsDict.close(); } @Override @@ -274,13 +339,15 @@ public class AndroidSpellCheckerService extends SpellCheckerService { for (Dictionary dict : oldWhitelistDictionaries.values()) { dict.close(); } - if (null != mContactsDictionary) { - // The synchronously loaded contacts dictionary should have been in one - // or several pools, but it is shielded against multiple closing and it's - // safe to call it several times. - final SynchronouslyLoadedContactsDictionary dictToClose = mContactsDictionary; - mContactsDictionary = null; - dictToClose.close(); + synchronized(mUseContactsLock) { + if (null != mContactsDictionary) { + // The synchronously loaded contacts dictionary should have been in one + // or several pools, but it is shielded against multiple closing and it's + // safe to call it several times. + final SynchronouslyLoadedContactsDictionary dictToClose = mContactsDictionary; + mContactsDictionary = null; + dictToClose.close(); + } } return false; } @@ -315,11 +382,16 @@ public class AndroidSpellCheckerService extends SpellCheckerService { mWhitelistDictionaries.put(localeStr, whitelistDictionary); } dictionaryCollection.addDictionary(whitelistDictionary); - if (null == mContactsDictionary) { - mContactsDictionary = new SynchronouslyLoadedContactsDictionary(this); + synchronized(mUseContactsLock) { + if (mUseContactsDictionary) { + if (null == mContactsDictionary) { + mContactsDictionary = new SynchronouslyLoadedContactsDictionary(this); + } + } + dictionaryCollection.addDictionary(mContactsDictionary); + mDictionaryCollectionsList.add( + new WeakReference<DictionaryCollection>(dictionaryCollection)); } - // TODO: add a setting to use or not contacts when checking spelling - dictionaryCollection.addDictionary(mContactsDictionary); return new DictAndProximity(dictionaryCollection, proximityInfo); } -- GitLab