am db5aedb5: Add an option to use contacts or not while spell checking

* commit 'db5aedb5a5eea5224e5a732b689c97eead2e35f4':
  Add an option to use contacts or not while spell checking
main
Jean Chalard 2011-11-30 14:01:55 -08:00 committed by Android Git Automerger
commit a5d2d235e9
5 changed files with 112 additions and 23 deletions

View File

@ -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>

View File

@ -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>

View File

@ -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"

View File

@ -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);
}
}
}

View File

@ -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);
}