Always show the typed word in recorrections.

Bug: 11330140
Bug: 17875601
Bug: 17623275
Change-Id: Ie4620f36f312c54c7b01b5f6cbdb0bc9171b6179
main
Jean Chalard 2014-10-08 14:40:03 +09:00
parent 41302021d6
commit bc18005948
7 changed files with 38 additions and 97 deletions

View File

@ -1627,7 +1627,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
} }
@Override @Override
public void showAddToDictionaryHint(final String word) { public void suggestAddingToDictionary(final String word, final boolean isFromSuggestionStrip) {
if (!hasSuggestionStripView()) { if (!hasSuggestionStripView()) {
return; return;
} }
@ -1637,7 +1637,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
} else { } else {
wordToShow = word; wordToShow = word;
} }
mSuggestionStripView.showAddToDictionaryHint(wordToShow); mSuggestionStripView.showAddToDictionaryHint(wordToShow,
isFromSuggestionStrip /* shouldShowWordToSave */);
} }
// This will show either an empty suggestion strip (if prediction is enabled) or // This will show either an empty suggestion strip (if prediction is enabled) or

View File

@ -413,28 +413,6 @@ public class SuggestedWords {
return isPrediction(mInputStyle); return isPrediction(mInputStyle);
} }
// SuggestedWords is an immutable object, as much as possible. We must not just remove
// words from the member ArrayList as some other parties may expect the object to never change.
// This is only ever called by recorrection at the moment, hence the ForRecorrection moniker.
public SuggestedWords getSuggestedWordsExcludingTypedWordForRecorrection() {
final ArrayList<SuggestedWordInfo> newSuggestions = new ArrayList<>();
String typedWord = null;
for (int i = 0; i < mSuggestedWordInfoList.size(); ++i) {
final SuggestedWordInfo info = mSuggestedWordInfoList.get(i);
if (!info.isKindOf(SuggestedWordInfo.KIND_TYPED)) {
newSuggestions.add(info);
} else {
assert(null == typedWord);
typedWord = info.mWord;
}
}
// We should never autocorrect, so we say the typed word is valid. Also, in this case,
// no auto-correction should take place hence willAutoCorrect = false.
return new SuggestedWords(newSuggestions, null /* rawSuggestions */, typedWord,
true /* typedWordValid */, false /* willAutoCorrect */, mIsObsoleteSuggestions,
SuggestedWords.INPUT_STYLE_RECORRECTION, NOT_A_SEQUENCE_NUMBER);
}
// Creates a new SuggestedWordInfo from the currently suggested words that removes all but the // Creates a new SuggestedWordInfo from the currently suggested words that removes all but the
// last word of all suggestions, separated by a space. This is necessary because when we commit // last word of all suggestions, separated by a space. This is necessary because when we commit
// a multiple-word suggestion, the IME only retains the last word as the composing word, and // a multiple-word suggestion, the IME only retains the last word as the composing word, and

View File

@ -349,7 +349,8 @@ public final class InputLogic {
inputTransaction.requireShiftUpdate(InputTransaction.SHIFT_UPDATE_NOW); inputTransaction.requireShiftUpdate(InputTransaction.SHIFT_UPDATE_NOW);
if (shouldShowAddToDictionaryHint) { if (shouldShowAddToDictionaryHint) {
mSuggestionStripViewAccessor.showAddToDictionaryHint(suggestion); mSuggestionStripViewAccessor.suggestAddingToDictionary(suggestion,
true /* isFromSuggestionStrip */);
} else { } else {
// If we're not showing the "Touch again to save", then update the suggestion strip. // If we're not showing the "Touch again to save", then update the suggestion strip.
// That's going to be predictions (or punctuation suggestions), so INPUT_STYLE_NONE. // That's going to be predictions (or punctuation suggestions), so INPUT_STYLE_NONE.
@ -1485,6 +1486,11 @@ public final class InputLogic {
if (numberOfCharsInWordBeforeCursor > expectedCursorPosition) return; if (numberOfCharsInWordBeforeCursor > expectedCursorPosition) return;
final ArrayList<SuggestedWordInfo> suggestions = new ArrayList<>(); final ArrayList<SuggestedWordInfo> suggestions = new ArrayList<>();
final String typedWord = range.mWord.toString(); final String typedWord = range.mWord.toString();
suggestions.add(new SuggestedWordInfo(typedWord,
SuggestedWords.MAX_SUGGESTIONS + 1,
SuggestedWordInfo.KIND_TYPED, Dictionary.DICTIONARY_USER_TYPED,
SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */,
SuggestedWordInfo.NOT_A_CONFIDENCE /* autoCommitFirstWordConfidence */));
if (!isResumableWord(settingsValues, typedWord)) { if (!isResumableWord(settingsValues, typedWord)) {
mSuggestionStripViewAccessor.setNeutralSuggestionStrip(); mSuggestionStripViewAccessor.setNeutralSuggestionStrip();
return; return;
@ -1517,30 +1523,14 @@ public final class InputLogic {
mConnection.maybeMoveTheCursorAroundAndRestoreToWorkaroundABug(); mConnection.maybeMoveTheCursorAroundAndRestoreToWorkaroundABug();
mConnection.setComposingRegion(expectedCursorPosition - numberOfCharsInWordBeforeCursor, mConnection.setComposingRegion(expectedCursorPosition - numberOfCharsInWordBeforeCursor,
expectedCursorPosition + range.getNumberOfCharsInWordAfterCursor()); expectedCursorPosition + range.getNumberOfCharsInWordAfterCursor());
if (suggestions.size() <= 0) { if (suggestions.size() <= 1) {
// If there weren't any suggestion spans on this word, suggestions#size() will be 1 // If there weren't any suggestion spans on this word, suggestions#size() will be 1
// if shouldIncludeResumedWordInSuggestions is true, 0 otherwise. In this case, we // if shouldIncludeResumedWordInSuggestions is true, 0 otherwise. In this case, we
// have no useful suggestions, so we will try to compute some for it instead. // have no useful suggestions, so we will try to compute some for it instead.
mInputLogicHandler.getSuggestedWords(Suggest.SESSION_ID_TYPING, mInputLogicHandler.getSuggestedWords(Suggest.SESSION_ID_TYPING,
SuggestedWords.NOT_A_SEQUENCE_NUMBER, new OnGetSuggestedWordsCallback() { SuggestedWords.NOT_A_SEQUENCE_NUMBER, new OnGetSuggestedWordsCallback() {
@Override @Override
public void onGetSuggestedWords( public void onGetSuggestedWords(final SuggestedWords suggestedWords) {
final SuggestedWords suggestedWordsIncludingTypedWord) {
final SuggestedWords suggestedWords;
if (suggestedWordsIncludingTypedWord.size() > 1) {
// We were able to compute new suggestions for this word.
// Remove the typed word, since we don't want to display it in this
// case. The #getSuggestedWordsExcludingTypedWordForRecorrection()
// method sets willAutoCorrect to false.
suggestedWords = suggestedWordsIncludingTypedWord
.getSuggestedWordsExcludingTypedWordForRecorrection();
} else {
// No saved suggestions, and we were unable to compute any good one
// either. Rather than displaying an empty suggestion strip, we'll
// display the original word alone in the middle.
// Since there is only one word, willAutoCorrect is false.
suggestedWords = suggestedWordsIncludingTypedWord;
}
mIsAutoCorrectionIndicatorOn = false; mIsAutoCorrectionIndicatorOn = false;
mLatinIME.mHandler.showSuggestionStrip(suggestedWords); mLatinIME.mHandler.showSuggestionStrip(suggestedWords);
}}); }});
@ -1684,7 +1674,8 @@ public final class InputLogic {
mConnection.getExpectedSelectionStart(), mConnection.getExpectedSelectionStart(),
mConnection.getExpectedSelectionEnd()); mConnection.getExpectedSelectionEnd());
} }
mSuggestionStripViewAccessor.showAddToDictionaryHint(originallyTypedWordString); mSuggestionStripViewAccessor.suggestAddingToDictionary(originallyTypedWordString,
false /* isFromSuggestionStrip */);
} else { } else {
// We have a separator between the word and the cursor: we should show predictions. // We have a separator between the word and the cursor: we should show predictions.
inputTransaction.setRequiresUpdateSuggestions(); inputTransaction.setRequiresUpdateSuggestions();

View File

@ -553,12 +553,12 @@ final class SuggestionStripLayoutHelper {
return countInStrip; return countInStrip;
} }
public void layoutAddToDictionaryHint(final String word, final ViewGroup addToDictionaryStrip) { public void layoutAddToDictionaryHint(final String word, final ViewGroup addToDictionaryStrip,
final boolean shouldShowUiToAcceptTypedWord = Settings.getInstance().getCurrent() final boolean shouldShowWordToSave) {
.mShouldShowLxxSuggestionUi; final boolean showsHintWithWord = shouldShowWordToSave
|| !Settings.getInstance().getCurrent().mShouldShowLxxSuggestionUi;
final int stripWidth = addToDictionaryStrip.getWidth(); final int stripWidth = addToDictionaryStrip.getWidth();
final int width = shouldShowUiToAcceptTypedWord ? stripWidth final int width = stripWidth - (showsHintWithWord ? mDividerWidth + mPadding * 2 : 0);
: stripWidth - mDividerWidth - mPadding * 2;
final TextView wordView = (TextView)addToDictionaryStrip.findViewById(R.id.word_to_save); final TextView wordView = (TextView)addToDictionaryStrip.findViewById(R.id.word_to_save);
wordView.setTextColor(mColorTypedWord); wordView.setTextColor(mColorTypedWord);
@ -569,7 +569,7 @@ final class SuggestionStripLayoutHelper {
wordView.setText(wordToSave); wordView.setText(wordToSave);
wordView.setTextScaleX(wordScaleX); wordView.setTextScaleX(wordScaleX);
setLayoutWeight(wordView, mCenterSuggestionWeight, ViewGroup.LayoutParams.MATCH_PARENT); setLayoutWeight(wordView, mCenterSuggestionWeight, ViewGroup.LayoutParams.MATCH_PARENT);
final int wordVisibility = shouldShowUiToAcceptTypedWord ? View.GONE : View.VISIBLE; final int wordVisibility = showsHintWithWord ? View.VISIBLE : View.GONE;
wordView.setVisibility(wordVisibility); wordView.setVisibility(wordVisibility);
addToDictionaryStrip.findViewById(R.id.word_to_save_divider).setVisibility(wordVisibility); addToDictionaryStrip.findViewById(R.id.word_to_save_divider).setVisibility(wordVisibility);
@ -579,12 +579,7 @@ final class SuggestionStripLayoutHelper {
final float hintWeight; final float hintWeight;
final TextView hintView = (TextView)addToDictionaryStrip.findViewById( final TextView hintView = (TextView)addToDictionaryStrip.findViewById(
R.id.hint_add_to_dictionary); R.id.hint_add_to_dictionary);
if (shouldShowUiToAcceptTypedWord) { if (showsHintWithWord) {
hintText = res.getText(R.string.hint_add_to_dictionary_without_word);
hintWidth = width;
hintWeight = 1.0f;
hintView.setGravity(Gravity.CENTER);
} else {
final boolean isRtlLanguage = (ViewCompat.getLayoutDirection(addToDictionaryStrip) final boolean isRtlLanguage = (ViewCompat.getLayoutDirection(addToDictionaryStrip)
== ViewCompat.LAYOUT_DIRECTION_RTL); == ViewCompat.LAYOUT_DIRECTION_RTL);
final String arrow = isRtlLanguage ? RIGHTWARDS_ARROW : LEFTWARDS_ARROW; final String arrow = isRtlLanguage ? RIGHTWARDS_ARROW : LEFTWARDS_ARROW;
@ -595,6 +590,11 @@ final class SuggestionStripLayoutHelper {
hintWidth = width - wordWidth; hintWidth = width - wordWidth;
hintWeight = 1.0f - mCenterSuggestionWeight; hintWeight = 1.0f - mCenterSuggestionWeight;
hintView.setGravity(Gravity.CENTER_VERTICAL | Gravity.START); hintView.setGravity(Gravity.CENTER_VERTICAL | Gravity.START);
} else {
hintText = res.getText(R.string.hint_add_to_dictionary_without_word);
hintWidth = width;
hintWeight = 1.0f;
hintView.setGravity(Gravity.CENTER);
} }
hintView.setTextColor(mColorAutoCorrect); hintView.setTextColor(mColorAutoCorrect);
final float hintScaleX = getTextScaleX(hintText, hintWidth, hintView.getPaint()); final float hintScaleX = getTextScaleX(hintText, hintWidth, hintView.getPaint());

View File

@ -231,8 +231,8 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick
return mStripVisibilityGroup.isShowingAddToDictionaryStrip(); return mStripVisibilityGroup.isShowingAddToDictionaryStrip();
} }
public void showAddToDictionaryHint(final String word) { public void showAddToDictionaryHint(final String word, final boolean shouldShowWordToSave) {
mLayoutHelper.layoutAddToDictionaryHint(word, mAddToDictionaryStrip); mLayoutHelper.layoutAddToDictionaryHint(word, mAddToDictionaryStrip, shouldShowWordToSave);
// {@link TextView#setTag()} is used to hold the word to be added to dictionary. The word // {@link TextView#setTag()} is used to hold the word to be added to dictionary. The word
// will be extracted at {@link #onClick(View)}. // will be extracted at {@link #onClick(View)}.
mAddToDictionaryStrip.setTag(word); mAddToDictionaryStrip.setTag(word);
@ -501,7 +501,7 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick
return; return;
} }
final Object tag = view.getTag(); final Object tag = view.getTag();
// {@link String} tag is set at {@link #showAddToDictionaryHint(String,CharSequence)}. // {@link String} tag is set at {@link #suggestAddingToDictionary(String,CharSequence)}.
if (tag instanceof String) { if (tag instanceof String) {
final String wordToSave = (String)tag; final String wordToSave = (String)tag;
mListener.addWordToUserDictionary(wordToSave); mListener.addWordToUserDictionary(wordToSave);

View File

@ -22,7 +22,7 @@ import com.android.inputmethod.latin.SuggestedWords;
* An object that gives basic control of a suggestion strip and some info on it. * An object that gives basic control of a suggestion strip and some info on it.
*/ */
public interface SuggestionStripViewAccessor { public interface SuggestionStripViewAccessor {
public void showAddToDictionaryHint(final String word); public void suggestAddingToDictionary(final String word, final boolean isFromSuggestionStrip);
public boolean isShowingAddToDictionaryHint(); public boolean isShowingAddToDictionaryHint();
public void dismissAddToDictionaryHint(); public void dismissAddToDictionaryHint();
public void setNeutralSuggestionStrip(); public void setNeutralSuggestionStrip();

View File

@ -59,40 +59,6 @@ public class SuggestedWordsTests extends AndroidTestCase {
SuggestedWordInfo.NOT_A_CONFIDENCE /* autoCommitFirstWordConfidence */); SuggestedWordInfo.NOT_A_CONFIDENCE /* autoCommitFirstWordConfidence */);
} }
public void testGetSuggestedWordsExcludingTypedWord() {
final String TYPED_WORD = "typed";
final int NUMBER_OF_ADDED_SUGGESTIONS = 5;
final int KIND_OF_SECOND_CORRECTION = SuggestedWordInfo.KIND_CORRECTION;
final ArrayList<SuggestedWordInfo> list = new ArrayList<>();
list.add(createTypedWordInfo(TYPED_WORD));
for (int i = 0; i < NUMBER_OF_ADDED_SUGGESTIONS; ++i) {
list.add(createCorrectionWordInfo(Integer.toString(i)));
}
final SuggestedWords words = new SuggestedWords(
list, null /* rawSuggestions */,
false /* typedWordValid */,
false /* willAutoCorrect */,
false /* isObsoleteSuggestions */,
SuggestedWords.INPUT_STYLE_NONE);
assertEquals(NUMBER_OF_ADDED_SUGGESTIONS + 1, words.size());
assertEquals("typed", words.getWord(0));
assertTrue(words.getInfo(0).isKindOf(SuggestedWordInfo.KIND_TYPED));
assertEquals("0", words.getWord(1));
assertTrue(words.getInfo(1).isKindOf(KIND_OF_SECOND_CORRECTION));
assertEquals("4", words.getWord(5));
assertTrue(words.getInfo(5).isKindOf(KIND_OF_SECOND_CORRECTION));
final SuggestedWords wordsWithoutTyped =
words.getSuggestedWordsExcludingTypedWordForRecorrection();
// Make sure that the typed word has indeed been excluded, by testing the size of the
// suggested words, the string and the kind of the top suggestion, which should match
// the string and kind of what we inserted after the typed word.
assertEquals(words.size() - 1, wordsWithoutTyped.size());
assertEquals("0", wordsWithoutTyped.getWord(0));
assertTrue(wordsWithoutTyped.getInfo(0).isKindOf(KIND_OF_SECOND_CORRECTION));
}
// Helper for testGetTransformedWordInfo // Helper for testGetTransformedWordInfo
private SuggestedWordInfo transformWordInfo(final String info, private SuggestedWordInfo transformWordInfo(final String info,
final int trailingSingleQuotesCount) { final int trailingSingleQuotesCount) {
@ -141,9 +107,14 @@ public class SuggestedWordsTests extends AndroidTestCase {
assertNotNull(typedWord); assertNotNull(typedWord);
assertEquals(TYPED_WORD, typedWord.mWord); assertEquals(TYPED_WORD, typedWord.mWord);
// Make sure getTypedWordInfoOrNull() returns null. // Make sure getTypedWordInfoOrNull() returns null when no typed word.
final SuggestedWords wordsWithoutTypedWord = list.remove(0);
wordsWithTypedWord.getSuggestedWordsExcludingTypedWordForRecorrection(); final SuggestedWords wordsWithoutTypedWord = new SuggestedWords(
list, null /* rawSuggestions */,
false /* typedWordValid */,
false /* willAutoCorrect */,
false /* isObsoleteSuggestions */,
SuggestedWords.INPUT_STYLE_NONE);
assertNull(wordsWithoutTypedWord.getTypedWordInfoOrNull()); assertNull(wordsWithoutTypedWord.getTypedWordInfoOrNull());
// Make sure getTypedWordInfoOrNull() returns null. // Make sure getTypedWordInfoOrNull() returns null.