Add an option to use contacts or not while spell checking

Bug: 5447495
Change-Id: Iffb09895676c3dd1a79d1699b0eac865282508d4
main
Jean Chalard 2011-11-10 08:21:42 +09:00
parent 70b8934f0e
commit db5aedb5a5
5 changed files with 112 additions and 23 deletions

View File

@ -31,11 +31,11 @@
<!-- Title for the spell checking service settings screen --> <!-- Title for the spell checking service settings screen -->
<string name="android_spell_checker_settings">Spell checking settings</string> <string name="android_spell_checker_settings">Spell checking settings</string>
<!-- Title for the "use proximity" option for spell checking [CHAR LIMIT=25] --> <!-- Title for the spell checker option to turn on/off contact names lookup [CHAR LIMIT=25] -->
<string name="use_proximity_option_title">Use proximity data</string> <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] --> <!-- Description for the spell checker option to turn on/off contact names lookup. [CHAR LIMIT=65] -->
<string name="use_proximity_option_summary">Use a keyboard-like proximity algorithm for spell checking</string> <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 --> <!-- Option to provide vibrate/haptic feedback on keypress -->
<string name="vibrate_on_keypress">Vibrate on keypress</string> <string name="vibrate_on_keypress">Vibrate on keypress</string>

View File

@ -18,9 +18,9 @@
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
android:title="@string/android_spell_checker_settings"> android:title="@string/android_spell_checker_settings">
<CheckBoxPreference <CheckBoxPreference
android:key="use_proximity" android:key="pref_spellcheck_use_contacts"
android:title="@string/use_proximity_option_title" android:title="@string/use_contacts_for_spellchecking_option_title"
android:summary="@string/use_proximity_option_summary" android:summary="@string/use_contacts_for_spellchecking_option_summary"
android:persistent="true" android:persistent="true"
android:defaultValue="true" /> android:defaultValue="true" />
</PreferenceScreen> </PreferenceScreen>

View File

@ -21,7 +21,8 @@
<!-- for the spell checker --> <!-- for the spell checker -->
<spell-checker xmlns:android="http://schemas.android.com/apk/res/android" <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 <subtype
android:label="@string/subtype_generic" android:label="@string/subtype_generic"
android:subtypeLocale="en" android:subtypeLocale="en"

View File

@ -18,6 +18,8 @@ package com.android.inputmethod.latin;
import com.android.inputmethod.keyboard.ProximityInfo; import com.android.inputmethod.keyboard.ProximityInfo;
import android.util.Log;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
@ -27,7 +29,7 @@ import java.util.concurrent.CopyOnWriteArrayList;
* Class for a collection of dictionaries that behave like one dictionary. * Class for a collection of dictionaries that behave like one dictionary.
*/ */
public class DictionaryCollection extends Dictionary { public class DictionaryCollection extends Dictionary {
private final String TAG = DictionaryCollection.class.getSimpleName();
protected final List<Dictionary> mDictionaries; protected final List<Dictionary> mDictionaries;
public DictionaryCollection() { public DictionaryCollection() {
@ -75,7 +77,21 @@ public class DictionaryCollection extends Dictionary {
dict.close(); dict.close();
} }
public void addDictionary(Dictionary newDict) { // Warning: this is not thread-safe. Take necessary precaution when calling.
if (null != newDict) mDictionaries.add(newDict); 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);
}
} }
} }

View File

@ -17,7 +17,9 @@
package com.android.inputmethod.latin.spellcheck; package com.android.inputmethod.latin.spellcheck;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Resources; import android.content.res.Resources;
import android.preference.PreferenceManager;
import android.service.textservice.SpellCheckerService; import android.service.textservice.SpellCheckerService;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log; 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.WhitelistDictionary;
import com.android.inputmethod.latin.WordComposer; import com.android.inputmethod.latin.WordComposer;
import java.lang.ref.WeakReference;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.Iterator;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.TreeMap; import java.util.TreeMap;
import java.util.HashSet;
/** /**
* Service for spell checking, using LatinIME's dictionaries and mechanisms. * 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 String TAG = AndroidSpellCheckerService.class.getSimpleName();
private static final boolean DBG = false; private static final boolean DBG = false;
private static final int POOL_SIZE = 2; 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_NONE = 0; // No caps, or mixed case
private static final int CAPITALIZE_FIRST = 1; // First only private static final int CAPITALIZE_FIRST = 1; // First only
private static final int CAPITALIZE_ALL = 2; // All caps private static final int CAPITALIZE_ALL = 2; // All caps
@ -84,6 +92,12 @@ public class AndroidSpellCheckerService extends SpellCheckerService {
private double mSuggestionThreshold; private double mSuggestionThreshold;
// The threshold for a suggestion to be considered "recommended". // The threshold for a suggestion to be considered "recommended".
private double mRecommendedThreshold; 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() { @Override public void onCreate() {
super.onCreate(); super.onCreate();
@ -91,6 +105,57 @@ public class AndroidSpellCheckerService extends SpellCheckerService {
Double.parseDouble(getString(R.string.spellchecker_suggestion_threshold_value)); Double.parseDouble(getString(R.string.spellchecker_suggestion_threshold_value));
mRecommendedThreshold = mRecommendedThreshold =
Double.parseDouble(getString(R.string.spellchecker_recommended_threshold_value)); 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 @Override
@ -274,13 +339,15 @@ public class AndroidSpellCheckerService extends SpellCheckerService {
for (Dictionary dict : oldWhitelistDictionaries.values()) { for (Dictionary dict : oldWhitelistDictionaries.values()) {
dict.close(); dict.close();
} }
if (null != mContactsDictionary) { synchronized(mUseContactsLock) {
// The synchronously loaded contacts dictionary should have been in one if (null != mContactsDictionary) {
// or several pools, but it is shielded against multiple closing and it's // The synchronously loaded contacts dictionary should have been in one
// safe to call it several times. // or several pools, but it is shielded against multiple closing and it's
final SynchronouslyLoadedContactsDictionary dictToClose = mContactsDictionary; // safe to call it several times.
mContactsDictionary = null; final SynchronouslyLoadedContactsDictionary dictToClose = mContactsDictionary;
dictToClose.close(); mContactsDictionary = null;
dictToClose.close();
}
} }
return false; return false;
} }
@ -315,11 +382,16 @@ public class AndroidSpellCheckerService extends SpellCheckerService {
mWhitelistDictionaries.put(localeStr, whitelistDictionary); mWhitelistDictionaries.put(localeStr, whitelistDictionary);
} }
dictionaryCollection.addDictionary(whitelistDictionary); dictionaryCollection.addDictionary(whitelistDictionary);
if (null == mContactsDictionary) { synchronized(mUseContactsLock) {
mContactsDictionary = new SynchronouslyLoadedContactsDictionary(this); 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); return new DictAndProximity(dictionaryCollection, proximityInfo);
} }