Show auto correction feedback
Bug: 3230726 Change-Id: Iecf6fc837952c4721f6b726edcf16179254179camain
parent
8ec36be4f5
commit
55b9d333c5
|
@ -24,7 +24,9 @@ import android.os.Message;
|
||||||
import android.text.Spannable;
|
import android.text.Spannable;
|
||||||
import android.text.SpannableString;
|
import android.text.SpannableString;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
import android.text.style.BackgroundColorSpan;
|
||||||
import android.text.style.CharacterStyle;
|
import android.text.style.CharacterStyle;
|
||||||
|
import android.text.style.ForegroundColorSpan;
|
||||||
import android.text.style.StyleSpan;
|
import android.text.style.StyleSpan;
|
||||||
import android.text.style.UnderlineSpan;
|
import android.text.style.UnderlineSpan;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
|
@ -57,22 +59,76 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo
|
||||||
private final int mColorOther;
|
private final int mColorOther;
|
||||||
private static final CharacterStyle BOLD_SPAN = new StyleSpan(Typeface.BOLD);
|
private static final CharacterStyle BOLD_SPAN = new StyleSpan(Typeface.BOLD);
|
||||||
private static final CharacterStyle UNDERLINE_SPAN = new UnderlineSpan();
|
private static final CharacterStyle UNDERLINE_SPAN = new UnderlineSpan();
|
||||||
|
private final CharacterStyle mInvertedForegroundColorSpan;
|
||||||
|
private final CharacterStyle mInvertedBackgroundColorSpan;
|
||||||
|
|
||||||
private boolean mShowingCompletions;
|
private boolean mShowingCompletions;
|
||||||
|
private boolean mShowingAutoCorrectionInverted;
|
||||||
|
|
||||||
private boolean mShowingAddToDictionary;
|
private boolean mShowingAddToDictionary;
|
||||||
|
|
||||||
private static final long DELAY_HIDE_PREVIEW = 1000;
|
private final UiHandler mHandler = new UiHandler();
|
||||||
|
|
||||||
|
private static class UpdateSuggestionsArgs {
|
||||||
|
public final List<CharSequence> mSuggestions;
|
||||||
|
public final boolean mCompletions;
|
||||||
|
public final boolean mTypedWordValid;
|
||||||
|
public final boolean mHaveMinimalSuggestion;
|
||||||
|
public UpdateSuggestionsArgs(List<CharSequence> suggestions, boolean completions,
|
||||||
|
boolean typedWordValid, boolean haveMinimalSuggestion) {
|
||||||
|
mSuggestions = suggestions;
|
||||||
|
mCompletions = completions;
|
||||||
|
mTypedWordValid = typedWordValid;
|
||||||
|
mHaveMinimalSuggestion = haveMinimalSuggestion;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class UiHandler extends Handler {
|
||||||
private static final int MSG_HIDE_PREVIEW = 0;
|
private static final int MSG_HIDE_PREVIEW = 0;
|
||||||
private final Handler mHandler = new Handler() {
|
private static final int MSG_UPDATE_SUGGESTION = 1;
|
||||||
|
|
||||||
|
private static final long DELAY_HIDE_PREVIEW = 1000;
|
||||||
|
private static final long DELAY_UPDATE_SUGGESTION = 300;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void dispatchMessage(Message msg) {
|
public void dispatchMessage(Message msg) {
|
||||||
switch (msg.what) {
|
switch (msg.what) {
|
||||||
case MSG_HIDE_PREVIEW:
|
case MSG_HIDE_PREVIEW:
|
||||||
hidePreview();
|
hidePreview();
|
||||||
break;
|
break;
|
||||||
|
case MSG_UPDATE_SUGGESTION:
|
||||||
|
UpdateSuggestionsArgs args = (UpdateSuggestionsArgs)msg.obj;
|
||||||
|
updateSuggestions(args.mSuggestions, args.mCompletions, args.mTypedWordValid,
|
||||||
|
args.mHaveMinimalSuggestion);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void postHidePreview() {
|
||||||
|
cancelHidePreview();
|
||||||
|
sendMessageDelayed(obtainMessage(MSG_HIDE_PREVIEW), DELAY_HIDE_PREVIEW);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cancelHidePreview() {
|
||||||
|
removeMessages(MSG_HIDE_PREVIEW);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void postUpdateSuggestions(List<CharSequence> suggestions, boolean completions,
|
||||||
|
boolean typedWordValid, boolean haveMinimalSuggestion) {
|
||||||
|
cancelUpdateSuggestions();
|
||||||
|
sendMessageDelayed(obtainMessage(MSG_UPDATE_SUGGESTION, new UpdateSuggestionsArgs(
|
||||||
|
suggestions, completions, typedWordValid, haveMinimalSuggestion)),
|
||||||
|
DELAY_UPDATE_SUGGESTION);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cancelUpdateSuggestions() {
|
||||||
|
removeMessages(MSG_UPDATE_SUGGESTION);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cancelAllMessages() {
|
||||||
|
cancelHidePreview();
|
||||||
|
cancelUpdateSuggestions();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -96,6 +152,8 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo
|
||||||
mColorNormal = res.getColor(R.color.candidate_normal);
|
mColorNormal = res.getColor(R.color.candidate_normal);
|
||||||
mColorRecommended = res.getColor(R.color.candidate_recommended);
|
mColorRecommended = res.getColor(R.color.candidate_recommended);
|
||||||
mColorOther = res.getColor(R.color.candidate_other);
|
mColorOther = res.getColor(R.color.candidate_other);
|
||||||
|
mInvertedForegroundColorSpan = new ForegroundColorSpan(mColorNormal ^ 0x00ffffff);
|
||||||
|
mInvertedBackgroundColorSpan = new BackgroundColorSpan(mColorNormal);
|
||||||
|
|
||||||
for (int i = 0; i < MAX_SUGGESTIONS; i++) {
|
for (int i = 0; i < MAX_SUGGESTIONS; i++) {
|
||||||
View v = inflater.inflate(R.layout.candidate, null);
|
View v = inflater.inflate(R.layout.candidate, null);
|
||||||
|
@ -123,6 +181,16 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo
|
||||||
|
|
||||||
public void setSuggestions(List<CharSequence> suggestions, boolean completions,
|
public void setSuggestions(List<CharSequence> suggestions, boolean completions,
|
||||||
boolean typedWordValid, boolean haveMinimalSuggestion) {
|
boolean typedWordValid, boolean haveMinimalSuggestion) {
|
||||||
|
if (mShowingAutoCorrectionInverted) {
|
||||||
|
mHandler.postUpdateSuggestions(suggestions, completions, typedWordValid,
|
||||||
|
haveMinimalSuggestion);
|
||||||
|
} else {
|
||||||
|
updateSuggestions(suggestions, completions, typedWordValid, haveMinimalSuggestion);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateSuggestions(List<CharSequence> suggestions, boolean completions,
|
||||||
|
boolean typedWordValid, boolean haveMinimalSuggestion) {
|
||||||
clear();
|
clear();
|
||||||
if (suggestions != null) {
|
if (suggestions != null) {
|
||||||
int insertCount = Math.min(suggestions.size(), MAX_SUGGESTIONS);
|
int insertCount = Math.min(suggestions.size(), MAX_SUGGESTIONS);
|
||||||
|
@ -141,8 +209,8 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo
|
||||||
if (suggestion == null) continue;
|
if (suggestion == null) continue;
|
||||||
final int wordLength = suggestion.length();
|
final int wordLength = suggestion.length();
|
||||||
|
|
||||||
View v = mWords.get(i);
|
final View v = mWords.get(i);
|
||||||
TextView tv = (TextView)v.findViewById(R.id.candidate_word);
|
final TextView tv = (TextView)v.findViewById(R.id.candidate_word);
|
||||||
tv.setTextColor(mColorNormal);
|
tv.setTextColor(mColorNormal);
|
||||||
if (haveMinimalSuggestion
|
if (haveMinimalSuggestion
|
||||||
&& ((i == 1 && !typedWordValid) || (i == 0 && typedWordValid))) {
|
&& ((i == 1 && !typedWordValid) || (i == 0 && typedWordValid))) {
|
||||||
|
@ -179,6 +247,22 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo
|
||||||
requestLayout();
|
requestLayout();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void onAutoCorrectionInverted(CharSequence autoCorrectedWord) {
|
||||||
|
// Displaying auto corrected word as inverted is enabled only when highlighting candidate
|
||||||
|
// with color is disabled.
|
||||||
|
if (mConfigCandidateHighlightFontColorEnabled)
|
||||||
|
return;
|
||||||
|
final TextView tv = (TextView)mWords.get(1).findViewById(R.id.candidate_word);
|
||||||
|
final Spannable word = new SpannableString(autoCorrectedWord);
|
||||||
|
final int wordLength = word.length();
|
||||||
|
word.setSpan(mInvertedBackgroundColorSpan, 0, wordLength,
|
||||||
|
Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
|
||||||
|
word.setSpan(mInvertedForegroundColorSpan, 0, wordLength,
|
||||||
|
Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
|
||||||
|
tv.setText(word);
|
||||||
|
mShowingAutoCorrectionInverted = true;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isShowingAddToDictionaryHint() {
|
public boolean isShowingAddToDictionaryHint() {
|
||||||
return mShowingAddToDictionary;
|
return mShowingAddToDictionary;
|
||||||
}
|
}
|
||||||
|
@ -209,6 +293,7 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo
|
||||||
// in LatinIME.pickSuggestionManually().
|
// in LatinIME.pickSuggestionManually().
|
||||||
mSuggestions.clear();
|
mSuggestions.clear();
|
||||||
mShowingAddToDictionary = false;
|
mShowingAddToDictionary = false;
|
||||||
|
mShowingAutoCorrectionInverted = false;
|
||||||
removeAllViews();
|
removeAllViews();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -236,8 +321,7 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo
|
||||||
previewPopup.showAtLocation(this, Gravity.NO_GRAVITY, posX, posY);
|
previewPopup.showAtLocation(this, Gravity.NO_GRAVITY, posX, posY);
|
||||||
}
|
}
|
||||||
previewText.setVisibility(VISIBLE);
|
previewText.setVisibility(VISIBLE);
|
||||||
mHandler.sendMessageDelayed(
|
mHandler.postHidePreview();
|
||||||
mHandler.obtainMessage(MSG_HIDE_PREVIEW), DELAY_HIDE_PREVIEW);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addToDictionary(CharSequence word) {
|
private void addToDictionary(CharSequence word) {
|
||||||
|
@ -273,7 +357,7 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo
|
||||||
@Override
|
@Override
|
||||||
public void onDetachedFromWindow() {
|
public void onDetachedFromWindow() {
|
||||||
super.onDetachedFromWindow();
|
super.onDetachedFromWindow();
|
||||||
mHandler.removeMessages(MSG_HIDE_PREVIEW);
|
mHandler.cancelAllMessages();
|
||||||
hidePreview();
|
hidePreview();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,10 +81,8 @@ import java.util.Locale;
|
||||||
/**
|
/**
|
||||||
* Input method implementation for Qwerty'ish keyboard.
|
* Input method implementation for Qwerty'ish keyboard.
|
||||||
*/
|
*/
|
||||||
public class LatinIME extends InputMethodService
|
public class LatinIME extends InputMethodService implements KeyboardActionListener,
|
||||||
implements KeyboardActionListener,
|
SharedPreferences.OnSharedPreferenceChangeListener, Tutorial.TutorialListener {
|
||||||
SharedPreferences.OnSharedPreferenceChangeListener,
|
|
||||||
Tutorial.TutorialListener {
|
|
||||||
private static final String TAG = "LatinIME";
|
private static final String TAG = "LatinIME";
|
||||||
private static final boolean PERF_DEBUG = false;
|
private static final boolean PERF_DEBUG = false;
|
||||||
private static final boolean DEBUG = false;
|
private static final boolean DEBUG = false;
|
||||||
|
@ -1167,9 +1165,7 @@ public class LatinIME extends InputMethodService
|
||||||
if (ic == null) return;
|
if (ic == null) return;
|
||||||
abortCorrection(false);
|
abortCorrection(false);
|
||||||
ic.beginBatchEdit();
|
ic.beginBatchEdit();
|
||||||
if (mPredicting) {
|
|
||||||
commitTyped(ic);
|
commitTyped(ic);
|
||||||
}
|
|
||||||
maybeRemovePreviousPeriod(text);
|
maybeRemovePreviousPeriod(text);
|
||||||
ic.commitText(text, 1);
|
ic.commitText(text, 1);
|
||||||
ic.endBatchEdit();
|
ic.endBatchEdit();
|
||||||
|
@ -1382,7 +1378,14 @@ public class LatinIME extends InputMethodService
|
||||||
doubleSpace();
|
doubleSpace();
|
||||||
}
|
}
|
||||||
if (pickedDefault) {
|
if (pickedDefault) {
|
||||||
TextEntryState.backToAcceptedDefault(mWord.getTypedWord());
|
CharSequence typedWord = mWord.getTypedWord();
|
||||||
|
TextEntryState.backToAcceptedDefault(typedWord);
|
||||||
|
if (!TextUtils.isEmpty(typedWord) && !typedWord.equals(mBestWord)) {
|
||||||
|
// TODO: Will call InputConnection.commitCorrection() here.
|
||||||
|
if (mCandidateView != null)
|
||||||
|
mCandidateView.onAutoCorrectionInverted(mBestWord);
|
||||||
|
}
|
||||||
|
setPunctuationSuggestions();
|
||||||
}
|
}
|
||||||
mKeyboardSwitcher.updateShiftState();
|
mKeyboardSwitcher.updateShiftState();
|
||||||
if (ic != null) {
|
if (ic != null) {
|
||||||
|
@ -1564,7 +1567,7 @@ public class LatinIME extends InputMethodService
|
||||||
if (mBestWord != null && mBestWord.length() > 0) {
|
if (mBestWord != null && mBestWord.length() > 0) {
|
||||||
TextEntryState.acceptedDefault(mWord.getTypedWord(), mBestWord);
|
TextEntryState.acceptedDefault(mWord.getTypedWord(), mBestWord);
|
||||||
mJustAccepted = true;
|
mJustAccepted = true;
|
||||||
pickSuggestion(mBestWord, false);
|
pickSuggestion(mBestWord);
|
||||||
// Add the word to the auto dictionary if it's not a known word
|
// Add the word to the auto dictionary if it's not a known word
|
||||||
addToDictionaries(mBestWord, AutoDictionary.FREQUENCY_FOR_TYPED);
|
addToDictionaries(mBestWord, AutoDictionary.FREQUENCY_FOR_TYPED);
|
||||||
return true;
|
return true;
|
||||||
|
@ -1615,7 +1618,7 @@ public class LatinIME extends InputMethodService
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mJustAccepted = true;
|
mJustAccepted = true;
|
||||||
pickSuggestion(suggestion, correcting);
|
pickSuggestion(suggestion);
|
||||||
// Add the word to the auto dictionary if it's not a known word
|
// Add the word to the auto dictionary if it's not a known word
|
||||||
if (index == 0) {
|
if (index == 0) {
|
||||||
addToDictionaries(suggestion, AutoDictionary.FREQUENCY_FOR_PICKED);
|
addToDictionaries(suggestion, AutoDictionary.FREQUENCY_FOR_PICKED);
|
||||||
|
@ -1660,10 +1663,8 @@ public class LatinIME extends InputMethodService
|
||||||
* retrieval.
|
* retrieval.
|
||||||
* @param suggestion the suggestion picked by the user to be committed to
|
* @param suggestion the suggestion picked by the user to be committed to
|
||||||
* the text field
|
* the text field
|
||||||
* @param correcting whether this is due to a correction of an existing
|
|
||||||
* word.
|
|
||||||
*/
|
*/
|
||||||
private void pickSuggestion(CharSequence suggestion, boolean correcting) {
|
private void pickSuggestion(CharSequence suggestion) {
|
||||||
KeyboardSwitcher switcher = mKeyboardSwitcher;
|
KeyboardSwitcher switcher = mKeyboardSwitcher;
|
||||||
if (!switcher.isKeyboardAvailable())
|
if (!switcher.isKeyboardAvailable())
|
||||||
return;
|
return;
|
||||||
|
@ -1676,11 +1677,6 @@ public class LatinIME extends InputMethodService
|
||||||
mPredicting = false;
|
mPredicting = false;
|
||||||
mCommittedLength = suggestion.length();
|
mCommittedLength = suggestion.length();
|
||||||
switcher.setPreferredLetters(null);
|
switcher.setPreferredLetters(null);
|
||||||
// If we just corrected a word, then don't show punctuations
|
|
||||||
if (!correcting) {
|
|
||||||
setPunctuationSuggestions();
|
|
||||||
}
|
|
||||||
switcher.updateShiftState();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue