Pass additionalFeaturesOptions for getSuggestions().

This fixes null pointer exceptions that are caused when
getSuggestion() is called from spell checker.

Change-Id: Ifc9e7abb900e1a4646e33c91022effde439673e4
main
Keisuke Kuroyanagi 2013-08-28 19:24:28 +09:00
parent 8e3a90e58f
commit fe87f5f417
15 changed files with 54 additions and 43 deletions

View File

@ -21,7 +21,6 @@ import android.util.SparseArray;
import com.android.inputmethod.keyboard.ProximityInfo; import com.android.inputmethod.keyboard.ProximityInfo;
import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
import com.android.inputmethod.latin.settings.AdditionalFeaturesSettingUtils;
import com.android.inputmethod.latin.settings.NativeSuggestOptions; import com.android.inputmethod.latin.settings.NativeSuggestOptions;
import com.android.inputmethod.latin.utils.CollectionUtils; import com.android.inputmethod.latin.utils.CollectionUtils;
import com.android.inputmethod.latin.utils.JniUtils; import com.android.inputmethod.latin.utils.JniUtils;
@ -120,15 +119,16 @@ public final class BinaryDictionary extends Dictionary {
@Override @Override
public ArrayList<SuggestedWordInfo> getSuggestions(final WordComposer composer, public ArrayList<SuggestedWordInfo> getSuggestions(final WordComposer composer,
final String prevWord, final ProximityInfo proximityInfo, final String prevWord, final ProximityInfo proximityInfo,
final boolean blockOffensiveWords) { final boolean blockOffensiveWords, final int[] additionalFeaturesOptions) {
return getSuggestionsWithSessionId(composer, prevWord, proximityInfo, blockOffensiveWords, return getSuggestionsWithSessionId(composer, prevWord, proximityInfo, blockOffensiveWords,
0 /* sessionId */); additionalFeaturesOptions, 0 /* sessionId */);
} }
@Override @Override
public ArrayList<SuggestedWordInfo> getSuggestionsWithSessionId(final WordComposer composer, public ArrayList<SuggestedWordInfo> getSuggestionsWithSessionId(final WordComposer composer,
final String prevWord, final ProximityInfo proximityInfo, final String prevWord, final ProximityInfo proximityInfo,
final boolean blockOffensiveWords, final int sessionId) { final boolean blockOffensiveWords, final int[] additionalFeaturesOptions,
final int sessionId) {
if (!isValidDictionary()) return null; if (!isValidDictionary()) return null;
Arrays.fill(mInputCodePoints, Constants.NOT_A_CODE); Arrays.fill(mInputCodePoints, Constants.NOT_A_CODE);
@ -148,8 +148,7 @@ public final class BinaryDictionary extends Dictionary {
final InputPointers ips = composer.getInputPointers(); final InputPointers ips = composer.getInputPointers();
final int inputSize = isGesture ? ips.getPointerSize() : composerSize; final int inputSize = isGesture ? ips.getPointerSize() : composerSize;
mNativeSuggestOptions.setIsGesture(isGesture); mNativeSuggestOptions.setIsGesture(isGesture);
mNativeSuggestOptions.setAdditionalFeaturesOptions( mNativeSuggestOptions.setAdditionalFeaturesOptions(additionalFeaturesOptions);
AdditionalFeaturesSettingUtils.getAdditionalNativeSuggestOptions());
// proximityInfo and/or prevWordForBigrams may not be null. // proximityInfo and/or prevWordForBigrams may not be null.
final int count = getSuggestionsNative(mNativeDict, proximityInfo.getNativeProximityInfo(), final int count = getSuggestionsNative(mNativeDict, proximityInfo.getNativeProximityInfo(),
getTraverseSession(sessionId).getSession(), ips.getXCoordinates(), getTraverseSession(sessionId).getSession(), ips.getXCoordinates(),

View File

@ -72,20 +72,23 @@ public abstract class Dictionary {
* @param prevWord the previous word, or null if none * @param prevWord the previous word, or null if none
* @param proximityInfo the object for key proximity. May be ignored by some implementations. * @param proximityInfo the object for key proximity. May be ignored by some implementations.
* @param blockOffensiveWords whether to block potentially offensive words * @param blockOffensiveWords whether to block potentially offensive words
* @param additionalFeaturesOptions options about additional features used for the suggestion.
* @return the list of suggestions (possibly null if none) * @return the list of suggestions (possibly null if none)
*/ */
// TODO: pass more context than just the previous word, to enable better suggestions (n-gram // TODO: pass more context than just the previous word, to enable better suggestions (n-gram
// and more) // and more)
abstract public ArrayList<SuggestedWordInfo> getSuggestions(final WordComposer composer, abstract public ArrayList<SuggestedWordInfo> getSuggestions(final WordComposer composer,
final String prevWord, final ProximityInfo proximityInfo, final String prevWord, final ProximityInfo proximityInfo,
final boolean blockOffensiveWords); final boolean blockOffensiveWords, final int[] additionalFeaturesOptions);
// The default implementation of this method ignores sessionId. // The default implementation of this method ignores sessionId.
// Subclasses that want to use sessionId need to override this method. // Subclasses that want to use sessionId need to override this method.
public ArrayList<SuggestedWordInfo> getSuggestionsWithSessionId(final WordComposer composer, public ArrayList<SuggestedWordInfo> getSuggestionsWithSessionId(final WordComposer composer,
final String prevWord, final ProximityInfo proximityInfo, final String prevWord, final ProximityInfo proximityInfo,
final boolean blockOffensiveWords, final int sessionId) { final boolean blockOffensiveWords, final int[] additionalFeaturesOptions,
return getSuggestions(composer, prevWord, proximityInfo, blockOffensiveWords); final int sessionId) {
return getSuggestions(composer, prevWord, proximityInfo, blockOffensiveWords,
additionalFeaturesOptions);
} }
/** /**
@ -156,7 +159,7 @@ public abstract class Dictionary {
@Override @Override
public ArrayList<SuggestedWordInfo> getSuggestions(final WordComposer composer, public ArrayList<SuggestedWordInfo> getSuggestions(final WordComposer composer,
final String prevWord, final ProximityInfo proximityInfo, final String prevWord, final ProximityInfo proximityInfo,
final boolean blockOffensiveWords) { final boolean blockOffensiveWords, final int[] additionalFeaturesOptions) {
return null; return null;
} }

View File

@ -58,18 +58,18 @@ public final class DictionaryCollection extends Dictionary {
@Override @Override
public ArrayList<SuggestedWordInfo> getSuggestions(final WordComposer composer, public ArrayList<SuggestedWordInfo> getSuggestions(final WordComposer composer,
final String prevWord, final ProximityInfo proximityInfo, final String prevWord, final ProximityInfo proximityInfo,
final boolean blockOffensiveWords) { final boolean blockOffensiveWords, final int[] additionalFeaturesOptions) {
final CopyOnWriteArrayList<Dictionary> dictionaries = mDictionaries; final CopyOnWriteArrayList<Dictionary> dictionaries = mDictionaries;
if (dictionaries.isEmpty()) return null; if (dictionaries.isEmpty()) return null;
// To avoid creating unnecessary objects, we get the list out of the first // To avoid creating unnecessary objects, we get the list out of the first
// dictionary and add the rest to it if not null, hence the get(0) // dictionary and add the rest to it if not null, hence the get(0)
ArrayList<SuggestedWordInfo> suggestions = dictionaries.get(0).getSuggestions(composer, ArrayList<SuggestedWordInfo> suggestions = dictionaries.get(0).getSuggestions(composer,
prevWord, proximityInfo, blockOffensiveWords); prevWord, proximityInfo, blockOffensiveWords, additionalFeaturesOptions);
if (null == suggestions) suggestions = CollectionUtils.newArrayList(); if (null == suggestions) suggestions = CollectionUtils.newArrayList();
final int length = dictionaries.size(); final int length = dictionaries.size();
for (int i = 1; i < length; ++ i) { for (int i = 1; i < length; ++ i) {
final ArrayList<SuggestedWordInfo> sugg = dictionaries.get(i).getSuggestions(composer, final ArrayList<SuggestedWordInfo> sugg = dictionaries.get(i).getSuggestions(composer,
prevWord, proximityInfo, blockOffensiveWords); prevWord, proximityInfo, blockOffensiveWords, additionalFeaturesOptions);
if (null != sugg) suggestions.addAll(sugg); if (null != sugg) suggestions.addAll(sugg);
} }
return suggestions; return suggestions;

View File

@ -92,7 +92,7 @@ public class DictionaryWriter extends AbstractDictionaryWriter {
@Override @Override
public ArrayList<SuggestedWordInfo> getSuggestions(final WordComposer composer, public ArrayList<SuggestedWordInfo> getSuggestions(final WordComposer composer,
final String prevWord, final ProximityInfo proximityInfo, final String prevWord, final ProximityInfo proximityInfo,
boolean blockOffensiveWords) { boolean blockOffensiveWords, final int[] additionalFeaturesOptions) {
// This class doesn't support suggestion. // This class doesn't support suggestion.
return null; return null;
} }

View File

@ -272,19 +272,19 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
@Override @Override
public ArrayList<SuggestedWordInfo> getSuggestions(final WordComposer composer, public ArrayList<SuggestedWordInfo> getSuggestions(final WordComposer composer,
final String prevWord, final ProximityInfo proximityInfo, final String prevWord, final ProximityInfo proximityInfo,
final boolean blockOffensiveWords) { final boolean blockOffensiveWords, final int[] additionalFeaturesOptions) {
asyncReloadDictionaryIfRequired(); asyncReloadDictionaryIfRequired();
// Write lock because getSuggestions in native updates session status. // Write lock because getSuggestions in native updates session status.
if (mLocalDictionaryController.writeLock().tryLock()) { if (mLocalDictionaryController.writeLock().tryLock()) {
try { try {
final ArrayList<SuggestedWordInfo> inMemDictSuggestion = final ArrayList<SuggestedWordInfo> inMemDictSuggestion =
mDictionaryWriter.getSuggestions(composer, prevWord, proximityInfo, mDictionaryWriter.getSuggestions(composer, prevWord, proximityInfo,
blockOffensiveWords); blockOffensiveWords, additionalFeaturesOptions);
// TODO: Remove checking mIsUpdatable and use native suggestion. // TODO: Remove checking mIsUpdatable and use native suggestion.
if (mBinaryDictionary != null && !mIsUpdatable) { if (mBinaryDictionary != null && !mIsUpdatable) {
final ArrayList<SuggestedWordInfo> binarySuggestion = final ArrayList<SuggestedWordInfo> binarySuggestion =
mBinaryDictionary.getSuggestions(composer, prevWord, proximityInfo, mBinaryDictionary.getSuggestions(composer, prevWord, proximityInfo,
blockOffensiveWords); blockOffensiveWords, additionalFeaturesOptions);
if (inMemDictSuggestion == null) { if (inMemDictSuggestion == null) {
return binarySuggestion; return binarySuggestion;
} else if (binarySuggestion == null) { } else if (binarySuggestion == null) {

View File

@ -210,7 +210,7 @@ public class ExpandableDictionary extends Dictionary {
@Override @Override
public ArrayList<SuggestedWordInfo> getSuggestions(final WordComposer composer, public ArrayList<SuggestedWordInfo> getSuggestions(final WordComposer composer,
final String prevWord, final ProximityInfo proximityInfo, final String prevWord, final ProximityInfo proximityInfo,
final boolean blockOffensiveWords) { final boolean blockOffensiveWords, final int[] additionalFeaturesOptions) {
if (composer.size() > 1) { if (composer.size() > 1) {
if (composer.size() >= Constants.DICTIONARY_MAX_WORD_LENGTH) { if (composer.size() >= Constants.DICTIONARY_MAX_WORD_LENGTH) {
return null; return null;

View File

@ -2323,6 +2323,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// whatever is *before* the half-committed word in the buffer, hence 2; if we aren't, we // whatever is *before* the half-committed word in the buffer, hence 2; if we aren't, we
// should just skip whitespace if any, so 1. // should just skip whitespace if any, so 1.
final SettingsValues currentSettings = mSettings.getCurrent(); final SettingsValues currentSettings = mSettings.getCurrent();
final int[] additionalFeaturesOptions = currentSettings.mAdditionalFeaturesSettingValues;
final String prevWord; final String prevWord;
if (currentSettings.mCurrentLanguageHasSpaces) { if (currentSettings.mCurrentLanguageHasSpaces) {
// If we are typing in a language with spaces we can just look up the previous // If we are typing in a language with spaces we can just look up the previous
@ -2335,7 +2336,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
} }
return suggest.getSuggestedWords(mWordComposer, prevWord, keyboard.getProximityInfo(), return suggest.getSuggestedWords(mWordComposer, prevWord, keyboard.getProximityInfo(),
currentSettings.mBlockPotentiallyOffensive, currentSettings.mBlockPotentiallyOffensive,
currentSettings.mCorrectionEnabled, sessionId); currentSettings.mCorrectionEnabled, additionalFeaturesOptions, sessionId);
} }
private SuggestedWords getSuggestedWordsOrOlderSuggestions(final int sessionId) { private SuggestedWords getSuggestedWordsOrOlderSuggestions(final int sessionId) {

View File

@ -214,21 +214,23 @@ public final class Suggest {
public SuggestedWords getSuggestedWords(final WordComposer wordComposer, public SuggestedWords getSuggestedWords(final WordComposer wordComposer,
final String prevWordForBigram, final ProximityInfo proximityInfo, final String prevWordForBigram, final ProximityInfo proximityInfo,
final boolean blockOffensiveWords, final boolean isCorrectionEnabled, final boolean blockOffensiveWords, final boolean isCorrectionEnabled,
final int sessionId) { final int[] additionalFeaturesOptions, final int sessionId) {
LatinImeLogger.onStartSuggestion(prevWordForBigram); LatinImeLogger.onStartSuggestion(prevWordForBigram);
if (wordComposer.isBatchMode()) { if (wordComposer.isBatchMode()) {
return getSuggestedWordsForBatchInput( return getSuggestedWordsForBatchInput(
wordComposer, prevWordForBigram, proximityInfo, blockOffensiveWords, sessionId); wordComposer, prevWordForBigram, proximityInfo, blockOffensiveWords,
additionalFeaturesOptions, sessionId);
} else { } else {
return getSuggestedWordsForTypingInput(wordComposer, prevWordForBigram, proximityInfo, return getSuggestedWordsForTypingInput(wordComposer, prevWordForBigram, proximityInfo,
blockOffensiveWords, isCorrectionEnabled); blockOffensiveWords, isCorrectionEnabled, additionalFeaturesOptions);
} }
} }
// Retrieves suggestions for the typing input. // Retrieves suggestions for the typing input.
private SuggestedWords getSuggestedWordsForTypingInput(final WordComposer wordComposer, private SuggestedWords getSuggestedWordsForTypingInput(final WordComposer wordComposer,
final String prevWordForBigram, final ProximityInfo proximityInfo, final String prevWordForBigram, final ProximityInfo proximityInfo,
final boolean blockOffensiveWords, final boolean isCorrectionEnabled) { final boolean blockOffensiveWords, final boolean isCorrectionEnabled,
final int[] additionalFeaturesOptions) {
final int trailingSingleQuotesCount = wordComposer.trailingSingleQuotesCount(); final int trailingSingleQuotesCount = wordComposer.trailingSingleQuotesCount();
final BoundedTreeSet suggestionsSet = new BoundedTreeSet(sSuggestedWordInfoComparator, final BoundedTreeSet suggestionsSet = new BoundedTreeSet(sSuggestedWordInfoComparator,
MAX_SUGGESTIONS); MAX_SUGGESTIONS);
@ -252,7 +254,8 @@ public final class Suggest {
for (final String key : mDictionaries.keySet()) { for (final String key : mDictionaries.keySet()) {
final Dictionary dictionary = mDictionaries.get(key); final Dictionary dictionary = mDictionaries.get(key);
suggestionsSet.addAll(dictionary.getSuggestions( suggestionsSet.addAll(dictionary.getSuggestions(
wordComposerForLookup, prevWordForBigram, proximityInfo, blockOffensiveWords)); wordComposerForLookup, prevWordForBigram, proximityInfo, blockOffensiveWords,
additionalFeaturesOptions));
} }
final String whitelistedWord; final String whitelistedWord;
@ -343,7 +346,8 @@ public final class Suggest {
// Retrieves suggestions for the batch input. // Retrieves suggestions for the batch input.
private SuggestedWords getSuggestedWordsForBatchInput(final WordComposer wordComposer, private SuggestedWords getSuggestedWordsForBatchInput(final WordComposer wordComposer,
final String prevWordForBigram, final ProximityInfo proximityInfo, final String prevWordForBigram, final ProximityInfo proximityInfo,
final boolean blockOffensiveWords, final int sessionId) { final boolean blockOffensiveWords, final int[] additionalFeaturesOptions,
final int sessionId) {
final BoundedTreeSet suggestionsSet = new BoundedTreeSet(sSuggestedWordInfoComparator, final BoundedTreeSet suggestionsSet = new BoundedTreeSet(sSuggestedWordInfoComparator,
MAX_SUGGESTIONS); MAX_SUGGESTIONS);
@ -357,7 +361,8 @@ public final class Suggest {
} }
final Dictionary dictionary = mDictionaries.get(key); final Dictionary dictionary = mDictionaries.get(key);
suggestionsSet.addAll(dictionary.getSuggestionsWithSessionId(wordComposer, suggestionsSet.addAll(dictionary.getSuggestionsWithSessionId(wordComposer,
prevWordForBigram, proximityInfo, blockOffensiveWords, sessionId)); prevWordForBigram, proximityInfo, blockOffensiveWords,
additionalFeaturesOptions, sessionId));
} }
for (SuggestedWordInfo wordInfo : suggestionsSet) { for (SuggestedWordInfo wordInfo : suggestionsSet) {

View File

@ -34,9 +34,10 @@ public final class SynchronouslyLoadedContactsBinaryDictionary extends ContactsB
@Override @Override
public synchronized ArrayList<SuggestedWordInfo> getSuggestions(final WordComposer codes, public synchronized ArrayList<SuggestedWordInfo> getSuggestions(final WordComposer codes,
final String prevWordForBigrams, final ProximityInfo proximityInfo, final String prevWordForBigrams, final ProximityInfo proximityInfo,
final boolean blockOffensiveWords) { final boolean blockOffensiveWords, final int[] additionalFeaturesOptions) {
syncReloadDictionaryIfRequired(); syncReloadDictionaryIfRequired();
return super.getSuggestions(codes, prevWordForBigrams, proximityInfo, blockOffensiveWords); return super.getSuggestions(codes, prevWordForBigrams, proximityInfo, blockOffensiveWords,
additionalFeaturesOptions);
} }
@Override @Override

View File

@ -37,9 +37,10 @@ public final class SynchronouslyLoadedUserBinaryDictionary extends UserBinaryDic
@Override @Override
public synchronized ArrayList<SuggestedWordInfo> getSuggestions(final WordComposer codes, public synchronized ArrayList<SuggestedWordInfo> getSuggestions(final WordComposer codes,
final String prevWordForBigrams, final ProximityInfo proximityInfo, final String prevWordForBigrams, final ProximityInfo proximityInfo,
final boolean blockOffensiveWords) { final boolean blockOffensiveWords, final int[] additionalFeaturesOptions) {
syncReloadDictionaryIfRequired(); syncReloadDictionaryIfRequired();
return super.getSuggestions(codes, prevWordForBigrams, proximityInfo, blockOffensiveWords); return super.getSuggestions(codes, prevWordForBigrams, proximityInfo, blockOffensiveWords,
additionalFeaturesOptions);
} }
@Override @Override

View File

@ -147,9 +147,9 @@ public class DynamicPersonalizationDictionaryWriter extends AbstractDictionaryWr
@Override @Override
public ArrayList<SuggestedWordInfo> getSuggestions(final WordComposer composer, public ArrayList<SuggestedWordInfo> getSuggestions(final WordComposer composer,
final String prevWord, final ProximityInfo proximityInfo, final String prevWord, final ProximityInfo proximityInfo,
boolean blockOffensiveWords) { boolean blockOffensiveWords, final int[] additionalFeaturesOptions) {
return mExpandableDictionary.getSuggestions(composer, prevWord, proximityInfo, return mExpandableDictionary.getSuggestions(composer, prevWord, proximityInfo,
blockOffensiveWords); blockOffensiveWords, additionalFeaturesOptions);
} }
@Override @Override

View File

@ -40,8 +40,4 @@ public class AdditionalFeaturesSettingUtils {
final SharedPreferences prefs, final int[] additionalFeaturesPreferences) { final SharedPreferences prefs, final int[] additionalFeaturesPreferences) {
// do nothing. // do nothing.
} }
public static int[] getAdditionalNativeSuggestOptions() {
return Settings.getInstance().getCurrent().mAdditionalFeaturesSettingValues;
}
} }

View File

@ -34,6 +34,9 @@ public class NativeSuggestOptions {
} }
public void setAdditionalFeaturesOptions(final int[] additionalOptions) { public void setAdditionalFeaturesOptions(final int[] additionalOptions) {
if (additionalOptions == null) {
return;
}
for (int i = 0; i < additionalOptions.length; i++) { for (int i = 0; i < additionalOptions.length; i++) {
setIntegerOption(OPTIONS_SIZE + i, additionalOptions[i]); setIntegerOption(OPTIONS_SIZE + i, additionalOptions[i]);
} }

View File

@ -301,13 +301,15 @@ public abstract class AndroidWordLevelSpellCheckerSession extends Session {
// TODO: make a spell checker option to block offensive words or not // TODO: make a spell checker option to block offensive words or not
final ArrayList<SuggestedWordInfo> suggestions = final ArrayList<SuggestedWordInfo> suggestions =
dictInfo.mDictionary.getSuggestions(composer, prevWord, dictInfo.mDictionary.getSuggestions(composer, prevWord,
dictInfo.getProximityInfo(), dictInfo.getProximityInfo(), true /* blockOffensiveWords */,
true /* blockOffensiveWords */); null /* additionalFeaturesOptions */);
if (suggestions != null) {
for (final SuggestedWordInfo suggestion : suggestions) { for (final SuggestedWordInfo suggestion : suggestions) {
final String suggestionStr = suggestion.mWord; final String suggestionStr = suggestion.mWord;
suggestionsGatherer.addWord(suggestionStr.toCharArray(), null, 0, suggestionsGatherer.addWord(suggestionStr.toCharArray(), null, 0,
suggestionStr.length(), suggestion.mScore); suggestionStr.length(), suggestion.mScore);
} }
}
isInDict = isInDictForAnyCapitalization(dictInfo.mDictionary, text, capitalizeType); isInDict = isInDictForAnyCapitalization(dictInfo.mDictionary, text, capitalizeType);
} finally { } finally {
if (null != dictInfo) { if (null != dictInfo) {

View File

@ -52,7 +52,7 @@ public final class DictionaryPool extends LinkedBlockingQueue<DictAndKeyboard> {
@Override @Override
public ArrayList<SuggestedWordInfo> getSuggestions(final WordComposer composer, public ArrayList<SuggestedWordInfo> getSuggestions(final WordComposer composer,
final String prevWord, final ProximityInfo proximityInfo, final String prevWord, final ProximityInfo proximityInfo,
final boolean blockOffensiveWords) { final boolean blockOffensiveWords, final int[] additionalFeaturesOptions) {
return noSuggestions; return noSuggestions;
} }
@Override @Override