Special case quotes at start and end of words
Single quote at start of word is not considered a part of a word any more. Single quote at the end of a word now behave like capitalization: lookup in the dictionary is done *disregarding* a final quote, and it is forcefully added back into the suggestions afterwards. Bug: 5566368 Change-Id: I14dd3815f4b743edba56d64a3abdf4b73d863a6amain
parent
7800a313f1
commit
c83359f974
|
@ -1503,6 +1503,9 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
|
||||||
mComposingStateManager.onFinishComposingText();
|
mComposingStateManager.onFinishComposingText();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (code == Keyboard.CODE_SINGLE_QUOTE && !isCursorTouchingWord()) {
|
||||||
|
mHasUncommittedTypedChars = false;
|
||||||
|
}
|
||||||
final KeyboardSwitcher switcher = mKeyboardSwitcher;
|
final KeyboardSwitcher switcher = mKeyboardSwitcher;
|
||||||
if (switcher.isShiftedOrShiftLocked()) {
|
if (switcher.isShiftedOrShiftLocked()) {
|
||||||
if (keyCodes == null || keyCodes[0] < Character.MIN_CODE_POINT
|
if (keyCodes == null || keyCodes[0] < Character.MIN_CODE_POINT
|
||||||
|
@ -1775,7 +1778,15 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
|
||||||
// a boolean flag. Right now this is handled with a slight hack in
|
// a boolean flag. Right now this is handled with a slight hack in
|
||||||
// WhitelistDictionary#shouldForciblyAutoCorrectFrom.
|
// WhitelistDictionary#shouldForciblyAutoCorrectFrom.
|
||||||
final boolean allowsToBeAutoCorrected = AutoCorrection.allowsToBeAutoCorrected(
|
final boolean allowsToBeAutoCorrected = AutoCorrection.allowsToBeAutoCorrected(
|
||||||
mSuggest.getUnigramDictionaries(), typedWord, preferCapitalization());
|
mSuggest.getUnigramDictionaries(),
|
||||||
|
// If the typed string ends with a single quote, for dictionary lookup purposes
|
||||||
|
// we behave as if the single quote was not here. Here, we are looking up the
|
||||||
|
// typed string in the dictionary (to avoid autocorrecting from an existing
|
||||||
|
// word, so for consistency this lookup should be made WITHOUT the trailing
|
||||||
|
// single quote.
|
||||||
|
wordComposer.isLastCharASingleQuote()
|
||||||
|
? typedWord.subSequence(0, typedWord.length() - 1) : typedWord,
|
||||||
|
preferCapitalization());
|
||||||
if (mCorrectionMode == Suggest.CORRECTION_FULL
|
if (mCorrectionMode == Suggest.CORRECTION_FULL
|
||||||
|| mCorrectionMode == Suggest.CORRECTION_FULL_BIGRAM) {
|
|| mCorrectionMode == Suggest.CORRECTION_FULL_BIGRAM) {
|
||||||
autoCorrectionAvailable |= (!allowsToBeAutoCorrected);
|
autoCorrectionAvailable |= (!allowsToBeAutoCorrected);
|
||||||
|
|
|
@ -20,6 +20,7 @@ import android.content.Context;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.android.inputmethod.keyboard.Keyboard;
|
||||||
import com.android.inputmethod.keyboard.ProximityInfo;
|
import com.android.inputmethod.keyboard.ProximityInfo;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
@ -81,6 +82,8 @@ public class Suggest implements Dictionary.WordCallback {
|
||||||
public static final String DICT_KEY_USER_BIGRAM = "user_bigram";
|
public static final String DICT_KEY_USER_BIGRAM = "user_bigram";
|
||||||
public static final String DICT_KEY_WHITELIST ="whitelist";
|
public static final String DICT_KEY_WHITELIST ="whitelist";
|
||||||
|
|
||||||
|
private static String SINGLE_QUOTE_AS_STRING = String.valueOf((char)Keyboard.CODE_SINGLE_QUOTE);
|
||||||
|
|
||||||
private static final boolean DBG = LatinImeLogger.sDBG;
|
private static final boolean DBG = LatinImeLogger.sDBG;
|
||||||
|
|
||||||
private AutoCorrection mAutoCorrection;
|
private AutoCorrection mAutoCorrection;
|
||||||
|
@ -101,11 +104,12 @@ public class Suggest implements Dictionary.WordCallback {
|
||||||
|
|
||||||
private ArrayList<CharSequence> mSuggestions = new ArrayList<CharSequence>();
|
private ArrayList<CharSequence> mSuggestions = new ArrayList<CharSequence>();
|
||||||
ArrayList<CharSequence> mBigramSuggestions = new ArrayList<CharSequence>();
|
ArrayList<CharSequence> mBigramSuggestions = new ArrayList<CharSequence>();
|
||||||
private CharSequence mTypedWord;
|
private CharSequence mConsideredWord;
|
||||||
|
|
||||||
// TODO: Remove these member variables by passing more context to addWord() callback method
|
// TODO: Remove these member variables by passing more context to addWord() callback method
|
||||||
private boolean mIsFirstCharCapitalized;
|
private boolean mIsFirstCharCapitalized;
|
||||||
private boolean mIsAllUpperCase;
|
private boolean mIsAllUpperCase;
|
||||||
|
private boolean mIsLastCharASingleQuote;
|
||||||
|
|
||||||
private int mCorrectionMode = CORRECTION_BASIC;
|
private int mCorrectionMode = CORRECTION_BASIC;
|
||||||
|
|
||||||
|
@ -295,17 +299,19 @@ public class Suggest implements Dictionary.WordCallback {
|
||||||
mAutoCorrection.init();
|
mAutoCorrection.init();
|
||||||
mIsFirstCharCapitalized = wordComposer.isFirstCharCapitalized();
|
mIsFirstCharCapitalized = wordComposer.isFirstCharCapitalized();
|
||||||
mIsAllUpperCase = wordComposer.isAllUpperCase();
|
mIsAllUpperCase = wordComposer.isAllUpperCase();
|
||||||
|
mIsLastCharASingleQuote = wordComposer.isLastCharASingleQuote();
|
||||||
collectGarbage(mSuggestions, mPrefMaxSuggestions);
|
collectGarbage(mSuggestions, mPrefMaxSuggestions);
|
||||||
Arrays.fill(mScores, 0);
|
Arrays.fill(mScores, 0);
|
||||||
|
|
||||||
// Save a lowercase version of the original word
|
final String typedWord = wordComposer.getTypedWord();
|
||||||
String typedWord = wordComposer.getTypedWord();
|
final String consideredWord = mIsLastCharASingleQuote
|
||||||
|
? typedWord.substring(0, typedWord.length() - 1) : typedWord;
|
||||||
if (typedWord != null) {
|
if (typedWord != null) {
|
||||||
// Treating USER_TYPED as UNIGRAM suggestion for logging now.
|
// Treating USER_TYPED as UNIGRAM suggestion for logging now.
|
||||||
LatinImeLogger.onAddSuggestedWord(typedWord, Suggest.DIC_USER_TYPED,
|
LatinImeLogger.onAddSuggestedWord(typedWord, Suggest.DIC_USER_TYPED,
|
||||||
Dictionary.DataType.UNIGRAM);
|
Dictionary.DataType.UNIGRAM);
|
||||||
}
|
}
|
||||||
mTypedWord = typedWord;
|
mConsideredWord = consideredWord;
|
||||||
|
|
||||||
if (wordComposer.size() <= 1 && (mCorrectionMode == CORRECTION_FULL_BIGRAM
|
if (wordComposer.size() <= 1 && (mCorrectionMode == CORRECTION_FULL_BIGRAM
|
||||||
|| mCorrectionMode == CORRECTION_BASIC)) {
|
|| mCorrectionMode == CORRECTION_BASIC)) {
|
||||||
|
@ -321,7 +327,7 @@ public class Suggest implements Dictionary.WordCallback {
|
||||||
for (final Dictionary dictionary : mBigramDictionaries.values()) {
|
for (final Dictionary dictionary : mBigramDictionaries.values()) {
|
||||||
dictionary.getBigrams(wordComposer, prevWordForBigram, this);
|
dictionary.getBigrams(wordComposer, prevWordForBigram, this);
|
||||||
}
|
}
|
||||||
if (TextUtils.isEmpty(typedWord)) {
|
if (TextUtils.isEmpty(consideredWord)) {
|
||||||
// Nothing entered: return all bigrams for the previous word
|
// Nothing entered: return all bigrams for the previous word
|
||||||
int insertCount = Math.min(mBigramSuggestions.size(), mPrefMaxSuggestions);
|
int insertCount = Math.min(mBigramSuggestions.size(), mPrefMaxSuggestions);
|
||||||
for (int i = 0; i < insertCount; ++i) {
|
for (int i = 0; i < insertCount; ++i) {
|
||||||
|
@ -330,7 +336,7 @@ public class Suggest implements Dictionary.WordCallback {
|
||||||
} else {
|
} else {
|
||||||
// Word entered: return only bigrams that match the first char of the typed word
|
// Word entered: return only bigrams that match the first char of the typed word
|
||||||
@SuppressWarnings("null")
|
@SuppressWarnings("null")
|
||||||
final char currentChar = typedWord.charAt(0);
|
final char currentChar = consideredWord.charAt(0);
|
||||||
// TODO: Must pay attention to locale when changing case.
|
// TODO: Must pay attention to locale when changing case.
|
||||||
final char currentCharUpper = Character.toUpperCase(currentChar);
|
final char currentCharUpper = Character.toUpperCase(currentChar);
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
@ -354,24 +360,32 @@ public class Suggest implements Dictionary.WordCallback {
|
||||||
if (key.equals(DICT_KEY_USER_UNIGRAM) || key.equals(DICT_KEY_WHITELIST))
|
if (key.equals(DICT_KEY_USER_UNIGRAM) || key.equals(DICT_KEY_WHITELIST))
|
||||||
continue;
|
continue;
|
||||||
final Dictionary dictionary = mUnigramDictionaries.get(key);
|
final Dictionary dictionary = mUnigramDictionaries.get(key);
|
||||||
dictionary.getWords(wordComposer, this, proximityInfo);
|
if (mIsLastCharASingleQuote) {
|
||||||
|
final WordComposer tmpWordComposer = new WordComposer(wordComposer);
|
||||||
|
tmpWordComposer.deleteLast();
|
||||||
|
dictionary.getWords(tmpWordComposer, this, proximityInfo);
|
||||||
|
} else {
|
||||||
|
dictionary.getWords(wordComposer, this, proximityInfo);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
final String typedWordString = typedWord == null ? null : typedWord.toString();
|
final String consideredWordString =
|
||||||
|
consideredWord == null ? null : consideredWord.toString();
|
||||||
|
|
||||||
CharSequence whitelistedWord = capitalizeWord(mIsAllUpperCase, mIsFirstCharCapitalized,
|
CharSequence whitelistedWord = capitalizeWord(mIsAllUpperCase, mIsFirstCharCapitalized,
|
||||||
mWhiteListDictionary.getWhitelistedWord(typedWordString));
|
mWhiteListDictionary.getWhitelistedWord(consideredWordString));
|
||||||
|
|
||||||
mAutoCorrection.updateAutoCorrectionStatus(mUnigramDictionaries, wordComposer,
|
mAutoCorrection.updateAutoCorrectionStatus(mUnigramDictionaries, wordComposer,
|
||||||
mSuggestions, mScores, typedWord, mAutoCorrectionThreshold, mCorrectionMode,
|
mSuggestions, mScores, consideredWord, mAutoCorrectionThreshold, mCorrectionMode,
|
||||||
whitelistedWord);
|
whitelistedWord);
|
||||||
|
|
||||||
if (whitelistedWord != null) {
|
if (whitelistedWord != null) {
|
||||||
mSuggestions.add(0, whitelistedWord);
|
mSuggestions.add(0, mIsLastCharASingleQuote
|
||||||
|
? whitelistedWord + SINGLE_QUOTE_AS_STRING : whitelistedWord);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typedWord != null) {
|
if (typedWord != null) {
|
||||||
mSuggestions.add(0, typedWordString);
|
mSuggestions.add(0, typedWord.toString());
|
||||||
}
|
}
|
||||||
Utils.removeDupes(mSuggestions);
|
Utils.removeDupes(mSuggestions);
|
||||||
|
|
||||||
|
@ -424,7 +438,7 @@ public class Suggest implements Dictionary.WordCallback {
|
||||||
int pos = 0;
|
int pos = 0;
|
||||||
|
|
||||||
// Check if it's the same word, only caps are different
|
// Check if it's the same word, only caps are different
|
||||||
if (Utils.equalsIgnoreCase(mTypedWord, word, offset, length)) {
|
if (Utils.equalsIgnoreCase(mConsideredWord, word, offset, length)) {
|
||||||
// TODO: remove this surrounding if clause and move this logic to
|
// TODO: remove this surrounding if clause and move this logic to
|
||||||
// getSuggestedWordBuilder.
|
// getSuggestedWordBuilder.
|
||||||
if (suggestions.size() > 0) {
|
if (suggestions.size() > 0) {
|
||||||
|
@ -486,6 +500,9 @@ public class Suggest implements Dictionary.WordCallback {
|
||||||
} else {
|
} else {
|
||||||
sb.append(word, offset, length);
|
sb.append(word, offset, length);
|
||||||
}
|
}
|
||||||
|
if (mIsLastCharASingleQuote) {
|
||||||
|
sb.appendCodePoint(Keyboard.CODE_SINGLE_QUOTE);
|
||||||
|
}
|
||||||
suggestions.add(pos, sb);
|
suggestions.add(pos, sb);
|
||||||
if (suggestions.size() > prefMaxSuggestions) {
|
if (suggestions.size() > prefMaxSuggestions) {
|
||||||
final CharSequence garbage = suggestions.remove(prefMaxSuggestions);
|
final CharSequence garbage = suggestions.remove(prefMaxSuggestions);
|
||||||
|
|
|
@ -16,9 +16,11 @@
|
||||||
|
|
||||||
package com.android.inputmethod.latin;
|
package com.android.inputmethod.latin;
|
||||||
|
|
||||||
|
import com.android.inputmethod.keyboard.Keyboard;
|
||||||
import com.android.inputmethod.keyboard.KeyDetector;
|
import com.android.inputmethod.keyboard.KeyDetector;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A place to store the currently composing word with information such as adjacent key codes as well
|
* A place to store the currently composing word with information such as adjacent key codes as well
|
||||||
|
@ -41,6 +43,8 @@ public class WordComposer {
|
||||||
private int mCapsCount;
|
private int mCapsCount;
|
||||||
|
|
||||||
private boolean mAutoCapitalized;
|
private boolean mAutoCapitalized;
|
||||||
|
// Cache this value for performance
|
||||||
|
private boolean mIsLastCharASingleQuote;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether the user chose to capitalize the first char of the word.
|
* Whether the user chose to capitalize the first char of the word.
|
||||||
|
@ -53,6 +57,7 @@ public class WordComposer {
|
||||||
mTypedWord = new StringBuilder(N);
|
mTypedWord = new StringBuilder(N);
|
||||||
mXCoordinates = new int[N];
|
mXCoordinates = new int[N];
|
||||||
mYCoordinates = new int[N];
|
mYCoordinates = new int[N];
|
||||||
|
mIsLastCharASingleQuote = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public WordComposer(WordComposer source) {
|
public WordComposer(WordComposer source) {
|
||||||
|
@ -62,11 +67,12 @@ public class WordComposer {
|
||||||
public void init(WordComposer source) {
|
public void init(WordComposer source) {
|
||||||
mCodes = new ArrayList<int[]>(source.mCodes);
|
mCodes = new ArrayList<int[]>(source.mCodes);
|
||||||
mTypedWord = new StringBuilder(source.mTypedWord);
|
mTypedWord = new StringBuilder(source.mTypedWord);
|
||||||
mXCoordinates = source.mXCoordinates;
|
mXCoordinates = Arrays.copyOf(source.mXCoordinates, source.mXCoordinates.length);
|
||||||
mYCoordinates = source.mYCoordinates;
|
mYCoordinates = Arrays.copyOf(source.mYCoordinates, source.mYCoordinates.length);
|
||||||
mCapsCount = source.mCapsCount;
|
mCapsCount = source.mCapsCount;
|
||||||
mIsFirstCharCapitalized = source.mIsFirstCharCapitalized;
|
mIsFirstCharCapitalized = source.mIsFirstCharCapitalized;
|
||||||
mAutoCapitalized = source.mAutoCapitalized;
|
mAutoCapitalized = source.mAutoCapitalized;
|
||||||
|
mIsLastCharASingleQuote = source.mIsLastCharASingleQuote;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -77,6 +83,7 @@ public class WordComposer {
|
||||||
mTypedWord.setLength(0);
|
mTypedWord.setLength(0);
|
||||||
mCapsCount = 0;
|
mCapsCount = 0;
|
||||||
mIsFirstCharCapitalized = false;
|
mIsFirstCharCapitalized = false;
|
||||||
|
mIsLastCharASingleQuote = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -126,6 +133,7 @@ public class WordComposer {
|
||||||
mIsFirstCharCapitalized = isFirstCharCapitalized(
|
mIsFirstCharCapitalized = isFirstCharCapitalized(
|
||||||
newIndex, primaryCode, mIsFirstCharCapitalized);
|
newIndex, primaryCode, mIsFirstCharCapitalized);
|
||||||
if (Character.isUpperCase(primaryCode)) mCapsCount++;
|
if (Character.isUpperCase(primaryCode)) mCapsCount++;
|
||||||
|
mIsLastCharASingleQuote = Keyboard.CODE_SINGLE_QUOTE == primaryCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -157,6 +165,10 @@ public class WordComposer {
|
||||||
}
|
}
|
||||||
if (size() == 0) {
|
if (size() == 0) {
|
||||||
mIsFirstCharCapitalized = false;
|
mIsFirstCharCapitalized = false;
|
||||||
|
mIsLastCharASingleQuote = false;
|
||||||
|
} else {
|
||||||
|
mIsLastCharASingleQuote =
|
||||||
|
Keyboard.CODE_SINGLE_QUOTE == mTypedWord.codePointAt(mTypedWord.length() - 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -179,6 +191,10 @@ public class WordComposer {
|
||||||
return mIsFirstCharCapitalized;
|
return mIsFirstCharCapitalized;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isLastCharASingleQuote() {
|
||||||
|
return mIsLastCharASingleQuote;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether or not all of the user typed chars are upper case
|
* Whether or not all of the user typed chars are upper case
|
||||||
* @return true if all user typed chars are upper case, false otherwise
|
* @return true if all user typed chars are upper case, false otherwise
|
||||||
|
|
Loading…
Reference in New Issue