am 91e7daad: Merge "Use CharSequence for spell checker to keep spans preserved" into lmp-dev

* commit '91e7daaddf72008b3e2f5a9cbc23ded56b6bdffa':
  Use CharSequence for spell checker to keep spans preserved
This commit is contained in:
Yohei Yukawa 2014-07-21 18:28:35 +00:00 committed by Android Git Automerger
commit 21036c2776
5 changed files with 43 additions and 32 deletions

View file

@ -16,10 +16,12 @@
package com.android.inputmethod.latin; package com.android.inputmethod.latin;
import java.util.Arrays; import android.text.TextUtils;
import com.android.inputmethod.latin.utils.StringUtils; import com.android.inputmethod.latin.utils.StringUtils;
import java.util.Arrays;
/** /**
* Class to represent information of previous words. This class is used to add n-gram entries * Class to represent information of previous words. This class is used to add n-gram entries
* into binary dictionaries, to get predictions, and to get suggestions. * into binary dictionaries, to get predictions, and to get suggestions.
@ -37,8 +39,8 @@ public class PrevWordsInfo {
public static final WordInfo EMPTY_WORD_INFO = new WordInfo(null); public static final WordInfo EMPTY_WORD_INFO = new WordInfo(null);
public static final WordInfo BEGINNING_OF_SENTENCE = new WordInfo(); public static final WordInfo BEGINNING_OF_SENTENCE = new WordInfo();
// This is an empty string when mIsBeginningOfSentence is true. // This is an empty char sequence when mIsBeginningOfSentence is true.
public final String mWord; public final CharSequence mWord;
// TODO: Have sentence separator. // TODO: Have sentence separator.
// Whether the current context is beginning of sentence or not. This is true when composing // Whether the current context is beginning of sentence or not. This is true when composing
// at the beginning of an input field or composing a word after a sentence separator. // at the beginning of an input field or composing a word after a sentence separator.
@ -50,7 +52,7 @@ public class PrevWordsInfo {
mIsBeginningOfSentence = true; mIsBeginningOfSentence = true;
} }
public WordInfo(final String word) { public WordInfo(final CharSequence word) {
mWord = word; mWord = word;
mIsBeginningOfSentence = false; mIsBeginningOfSentence = false;
} }
@ -73,7 +75,7 @@ public class PrevWordsInfo {
return mWord == wordInfo.mWord return mWord == wordInfo.mWord
&& mIsBeginningOfSentence == wordInfo.mIsBeginningOfSentence; && mIsBeginningOfSentence == wordInfo.mIsBeginningOfSentence;
} }
return mWord.equals(wordInfo.mWord) return TextUtils.equals(mWord, wordInfo.mWord)
&& mIsBeginningOfSentence == wordInfo.mIsBeginningOfSentence; && mIsBeginningOfSentence == wordInfo.mIsBeginningOfSentence;
} }
} }

View file

@ -17,6 +17,7 @@
package com.android.inputmethod.latin.personalization; package com.android.inputmethod.latin.personalization;
import android.content.Context; import android.content.Context;
import android.text.TextUtils;
import com.android.inputmethod.annotations.UsedForTesting; import com.android.inputmethod.annotations.UsedForTesting;
import com.android.inputmethod.latin.Constants; import com.android.inputmethod.latin.Constants;
@ -60,7 +61,7 @@ public class UserHistoryDictionary extends DecayingExpandableBinaryDictionaryBas
public static void addToDictionary(final ExpandableBinaryDictionary userHistoryDictionary, public static void addToDictionary(final ExpandableBinaryDictionary userHistoryDictionary,
final PrevWordsInfo prevWordsInfo, final String word, final boolean isValid, final PrevWordsInfo prevWordsInfo, final String word, final boolean isValid,
final int timestamp, final DistracterFilter distracterFilter) { final int timestamp, final DistracterFilter distracterFilter) {
final String prevWord = prevWordsInfo.mPrevWordsInfo[0].mWord; final CharSequence prevWord = prevWordsInfo.mPrevWordsInfo[0].mWord;
if (word.length() >= Constants.DICTIONARY_MAX_WORD_LENGTH || if (word.length() >= Constants.DICTIONARY_MAX_WORD_LENGTH ||
(prevWord != null && prevWord.length() >= Constants.DICTIONARY_MAX_WORD_LENGTH)) { (prevWord != null && prevWord.length() >= Constants.DICTIONARY_MAX_WORD_LENGTH)) {
return; return;
@ -71,7 +72,7 @@ public class UserHistoryDictionary extends DecayingExpandableBinaryDictionaryBas
null /* shortcutTarget */, 0 /* shortcutFreq */, false /* isNotAWord */, null /* shortcutTarget */, 0 /* shortcutFreq */, false /* isNotAWord */,
false /* isBlacklisted */, timestamp, distracterFilter); false /* isBlacklisted */, timestamp, distracterFilter);
// Do not insert a word as a bigram of itself // Do not insert a word as a bigram of itself
if (word.equals(prevWord)) { if (TextUtils.equals(word, prevWord)) {
return; return;
} }
if (null != prevWord) { if (null != prevWord) {

View file

@ -24,7 +24,9 @@ import android.view.textservice.SentenceSuggestionsInfo;
import android.view.textservice.SuggestionsInfo; import android.view.textservice.SuggestionsInfo;
import android.view.textservice.TextInfo; import android.view.textservice.TextInfo;
import com.android.inputmethod.compat.TextInfoCompatUtils;
import com.android.inputmethod.latin.PrevWordsInfo; import com.android.inputmethod.latin.PrevWordsInfo;
import com.android.inputmethod.latin.utils.StringUtils;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Locale; import java.util.Locale;
@ -42,15 +44,15 @@ public final class AndroidSpellCheckerSession extends AndroidWordLevelSpellCheck
private SentenceSuggestionsInfo fixWronglyInvalidatedWordWithSingleQuote(TextInfo ti, private SentenceSuggestionsInfo fixWronglyInvalidatedWordWithSingleQuote(TextInfo ti,
SentenceSuggestionsInfo ssi) { SentenceSuggestionsInfo ssi) {
final String typedText = ti.getText(); final CharSequence typedText = TextInfoCompatUtils.getCharSequenceOrString(ti);
if (!typedText.contains(AndroidSpellCheckerService.SINGLE_QUOTE)) { if (!typedText.toString().contains(AndroidSpellCheckerService.SINGLE_QUOTE)) {
return null; return null;
} }
final int N = ssi.getSuggestionsCount(); final int N = ssi.getSuggestionsCount();
final ArrayList<Integer> additionalOffsets = new ArrayList<>(); final ArrayList<Integer> additionalOffsets = new ArrayList<>();
final ArrayList<Integer> additionalLengths = new ArrayList<>(); final ArrayList<Integer> additionalLengths = new ArrayList<>();
final ArrayList<SuggestionsInfo> additionalSuggestionsInfos = new ArrayList<>(); final ArrayList<SuggestionsInfo> additionalSuggestionsInfos = new ArrayList<>();
String currentWord = null; CharSequence currentWord = null;
for (int i = 0; i < N; ++i) { for (int i = 0; i < N; ++i) {
final SuggestionsInfo si = ssi.getSuggestionsInfoAt(i); final SuggestionsInfo si = ssi.getSuggestionsInfoAt(i);
final int flags = si.getSuggestionsAttributes(); final int flags = si.getSuggestionsAttributes();
@ -59,32 +61,33 @@ public final class AndroidSpellCheckerSession extends AndroidWordLevelSpellCheck
} }
final int offset = ssi.getOffsetAt(i); final int offset = ssi.getOffsetAt(i);
final int length = ssi.getLengthAt(i); final int length = ssi.getLengthAt(i);
final String subText = typedText.substring(offset, offset + length); final CharSequence subText = typedText.subSequence(offset, offset + length);
final PrevWordsInfo prevWordsInfo = final PrevWordsInfo prevWordsInfo =
new PrevWordsInfo(new PrevWordsInfo.WordInfo(currentWord)); new PrevWordsInfo(new PrevWordsInfo.WordInfo(currentWord));
currentWord = subText; currentWord = subText;
if (!subText.contains(AndroidSpellCheckerService.SINGLE_QUOTE)) { if (!subText.toString().contains(AndroidSpellCheckerService.SINGLE_QUOTE)) {
continue; continue;
} }
final String[] splitTexts = final CharSequence[] splitTexts = StringUtils.split(subText,
subText.split(AndroidSpellCheckerService.SINGLE_QUOTE, -1); AndroidSpellCheckerService.SINGLE_QUOTE,
true /* preserveTrailingEmptySegments */ );
if (splitTexts == null || splitTexts.length <= 1) { if (splitTexts == null || splitTexts.length <= 1) {
continue; continue;
} }
final int splitNum = splitTexts.length; final int splitNum = splitTexts.length;
for (int j = 0; j < splitNum; ++j) { for (int j = 0; j < splitNum; ++j) {
final String splitText = splitTexts[j]; final CharSequence splitText = splitTexts[j];
if (TextUtils.isEmpty(splitText)) { if (TextUtils.isEmpty(splitText)) {
continue; continue;
} }
if (mSuggestionsCache.getSuggestionsFromCache(splitText, prevWordsInfo) == null) { if (mSuggestionsCache.getSuggestionsFromCache(splitText.toString(), prevWordsInfo)
== null) {
continue; continue;
} }
final int newLength = splitText.length(); final int newLength = splitText.length();
// Neither RESULT_ATTR_IN_THE_DICTIONARY nor RESULT_ATTR_LOOKS_LIKE_TYPO // Neither RESULT_ATTR_IN_THE_DICTIONARY nor RESULT_ATTR_LOOKS_LIKE_TYPO
final int newFlags = 0; final int newFlags = 0;
final SuggestionsInfo newSi = final SuggestionsInfo newSi = new SuggestionsInfo(newFlags, EMPTY_STRING_ARRAY);
new SuggestionsInfo(newFlags, EMPTY_STRING_ARRAY);
newSi.setCookieAndSequence(si.getCookie(), si.getSequence()); newSi.setCookieAndSequence(si.getCookie(), si.getSequence());
if (DBG) { if (DBG) {
Log.d(TAG, "Override and remove old span over: " + splitText + ", " Log.d(TAG, "Override and remove old span over: " + splitText + ", "
@ -194,20 +197,22 @@ public final class AndroidSpellCheckerSession extends AndroidWordLevelSpellCheck
final int length = textInfos.length; final int length = textInfos.length;
final SuggestionsInfo[] retval = new SuggestionsInfo[length]; final SuggestionsInfo[] retval = new SuggestionsInfo[length];
for (int i = 0; i < length; ++i) { for (int i = 0; i < length; ++i) {
final String prevWord; final CharSequence prevWord;
if (sequentialWords && i > 0) { if (sequentialWords && i > 0) {
final String prevWordCandidate = textInfos[i - 1].getText(); final TextInfo prevTextInfo = textInfos[i - 1];
// Note that an empty string would be used to indicate the initial word final CharSequence prevWordCandidate =
// in the future. TextInfoCompatUtils.getCharSequenceOrString(prevTextInfo);
prevWord = TextUtils.isEmpty(prevWordCandidate) ? null : prevWordCandidate; // Note that an empty string would be used to indicate the initial word
// in the future.
prevWord = TextUtils.isEmpty(prevWordCandidate) ? null : prevWordCandidate;
} else { } else {
prevWord = null; prevWord = null;
} }
final PrevWordsInfo prevWordsInfo = final PrevWordsInfo prevWordsInfo =
new PrevWordsInfo(new PrevWordsInfo.WordInfo(prevWord)); new PrevWordsInfo(new PrevWordsInfo.WordInfo(prevWord));
retval[i] = onGetSuggestionsInternal(textInfos[i], prevWordsInfo, suggestionsLimit); final TextInfo textInfo = textInfos[i];
retval[i].setCookieAndSequence(textInfos[i].getCookie(), retval[i] = onGetSuggestionsInternal(textInfo, prevWordsInfo, suggestionsLimit);
textInfos[i].getSequence()); retval[i].setCookieAndSequence(textInfo.getCookie(), textInfo.getSequence());
} }
return retval; return retval;
} finally { } finally {

View file

@ -21,6 +21,7 @@ import android.view.textservice.SentenceSuggestionsInfo;
import android.view.textservice.SuggestionsInfo; import android.view.textservice.SuggestionsInfo;
import android.view.textservice.TextInfo; import android.view.textservice.TextInfo;
import com.android.inputmethod.compat.TextInfoCompatUtils;
import com.android.inputmethod.latin.Constants; import com.android.inputmethod.latin.Constants;
import com.android.inputmethod.latin.settings.SpacingAndPunctuations; import com.android.inputmethod.latin.settings.SpacingAndPunctuations;
import com.android.inputmethod.latin.utils.RunInLocale; import com.android.inputmethod.latin.utils.RunInLocale;
@ -127,7 +128,8 @@ public class SentenceLevelAdapter {
public SentenceTextInfoParams getSplitWords(TextInfo originalTextInfo) { public SentenceTextInfoParams getSplitWords(TextInfo originalTextInfo) {
final WordIterator wordIterator = mWordIterator; final WordIterator wordIterator = mWordIterator;
final CharSequence originalText = originalTextInfo.getText(); final CharSequence originalText =
TextInfoCompatUtils.getCharSequenceOrString(originalTextInfo);
final int cookie = originalTextInfo.getCookie(); final int cookie = originalTextInfo.getCookie();
final int start = -1; final int start = -1;
final int end = originalText.length(); final int end = originalText.length();
@ -136,8 +138,9 @@ public class SentenceLevelAdapter {
int wordEnd = wordIterator.getEndOfWord(originalText, wordStart); int wordEnd = wordIterator.getEndOfWord(originalText, wordStart);
while (wordStart <= end && wordEnd != -1 && wordStart != -1) { while (wordStart <= end && wordEnd != -1 && wordStart != -1) {
if (wordEnd >= start && wordEnd > wordStart) { if (wordEnd >= start && wordEnd > wordStart) {
final String query = originalText.subSequence(wordStart, wordEnd).toString(); CharSequence subSequence = originalText.subSequence(wordStart, wordEnd).toString();
final TextInfo ti = new TextInfo(query, cookie, query.hashCode()); final TextInfo ti = TextInfoCompatUtils.newInstance(subSequence, 0,
subSequence.length(), cookie, subSequence.hashCode());
wordItems.add(new SentenceWordItem(ti, wordStart, wordEnd)); wordItems.add(new SentenceWordItem(ti, wordStart, wordEnd));
} }
wordStart = wordIterator.getBeginningOfNextWord(originalText, wordEnd); wordStart = wordIterator.getBeginningOfNextWord(originalText, wordEnd);

View file

@ -43,7 +43,7 @@ public final class LanguageModelParam {
private static final int BIGRAM_PROBABILITY_FOR_VALID_WORD = 10; private static final int BIGRAM_PROBABILITY_FOR_VALID_WORD = 10;
private static final int BIGRAM_PROBABILITY_FOR_OOV_WORD = Dictionary.NOT_A_PROBABILITY; private static final int BIGRAM_PROBABILITY_FOR_OOV_WORD = Dictionary.NOT_A_PROBABILITY;
public final String mTargetWord; public final CharSequence mTargetWord;
public final int[] mWord0; public final int[] mWord0;
public final int[] mWord1; public final int[] mWord1;
// TODO: this needs to be a list of shortcuts // TODO: this needs to be a list of shortcuts
@ -57,13 +57,13 @@ public final class LanguageModelParam {
public final int mTimestamp; public final int mTimestamp;
// Constructor for unigram. TODO: support shortcuts // Constructor for unigram. TODO: support shortcuts
public LanguageModelParam(final String word, final int unigramProbability, public LanguageModelParam(final CharSequence word, final int unigramProbability,
final int timestamp) { final int timestamp) {
this(null /* word0 */, word, unigramProbability, Dictionary.NOT_A_PROBABILITY, timestamp); this(null /* word0 */, word, unigramProbability, Dictionary.NOT_A_PROBABILITY, timestamp);
} }
// Constructor for unigram and bigram. // Constructor for unigram and bigram.
public LanguageModelParam(final String word0, final String word1, public LanguageModelParam(final CharSequence word0, final CharSequence word1,
final int unigramProbability, final int bigramProbability, final int unigramProbability, final int bigramProbability,
final int timestamp) { final int timestamp) {
mTargetWord = word1; mTargetWord = word1;