diff --git a/java/src/com/android/inputmethod/latin/CandidateView.java b/java/src/com/android/inputmethod/latin/CandidateView.java index 99f8a6736..74e6a01b5 100644 --- a/java/src/com/android/inputmethod/latin/CandidateView.java +++ b/java/src/com/android/inputmethod/latin/CandidateView.java @@ -24,7 +24,9 @@ import android.os.Message; import android.text.Spannable; import android.text.SpannableString; import android.text.TextUtils; +import android.text.style.BackgroundColorSpan; import android.text.style.CharacterStyle; +import android.text.style.ForegroundColorSpan; import android.text.style.StyleSpan; import android.text.style.UnderlineSpan; import android.util.AttributeSet; @@ -57,22 +59,76 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo private final int mColorOther; private static final CharacterStyle BOLD_SPAN = new StyleSpan(Typeface.BOLD); private static final CharacterStyle UNDERLINE_SPAN = new UnderlineSpan(); + private final CharacterStyle mInvertedForegroundColorSpan; + private final CharacterStyle mInvertedBackgroundColorSpan; private boolean mShowingCompletions; + private boolean mShowingAutoCorrectionInverted; private boolean mShowingAddToDictionary; - private static final long DELAY_HIDE_PREVIEW = 1000; - private static final int MSG_HIDE_PREVIEW = 0; - private final Handler mHandler = new Handler() { + private final UiHandler mHandler = new UiHandler(); + + private static class UpdateSuggestionsArgs { + public final List mSuggestions; + public final boolean mCompletions; + public final boolean mTypedWordValid; + public final boolean mHaveMinimalSuggestion; + public UpdateSuggestionsArgs(List 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_UPDATE_SUGGESTION = 1; + + private static final long DELAY_HIDE_PREVIEW = 1000; + private static final long DELAY_UPDATE_SUGGESTION = 300; + @Override public void dispatchMessage(Message msg) { switch (msg.what) { case MSG_HIDE_PREVIEW: hidePreview(); 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 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); mColorRecommended = res.getColor(R.color.candidate_recommended); mColorOther = res.getColor(R.color.candidate_other); + mInvertedForegroundColorSpan = new ForegroundColorSpan(mColorNormal ^ 0x00ffffff); + mInvertedBackgroundColorSpan = new BackgroundColorSpan(mColorNormal); for (int i = 0; i < MAX_SUGGESTIONS; i++) { View v = inflater.inflate(R.layout.candidate, null); @@ -123,6 +181,16 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo public void setSuggestions(List suggestions, boolean completions, boolean typedWordValid, boolean haveMinimalSuggestion) { + if (mShowingAutoCorrectionInverted) { + mHandler.postUpdateSuggestions(suggestions, completions, typedWordValid, + haveMinimalSuggestion); + } else { + updateSuggestions(suggestions, completions, typedWordValid, haveMinimalSuggestion); + } + } + + private void updateSuggestions(List suggestions, boolean completions, + boolean typedWordValid, boolean haveMinimalSuggestion) { clear(); if (suggestions != null) { int insertCount = Math.min(suggestions.size(), MAX_SUGGESTIONS); @@ -141,8 +209,8 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo if (suggestion == null) continue; final int wordLength = suggestion.length(); - View v = mWords.get(i); - TextView tv = (TextView)v.findViewById(R.id.candidate_word); + final View v = mWords.get(i); + final TextView tv = (TextView)v.findViewById(R.id.candidate_word); tv.setTextColor(mColorNormal); if (haveMinimalSuggestion && ((i == 1 && !typedWordValid) || (i == 0 && typedWordValid))) { @@ -179,6 +247,22 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo 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() { return mShowingAddToDictionary; } @@ -209,6 +293,7 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo // in LatinIME.pickSuggestionManually(). mSuggestions.clear(); mShowingAddToDictionary = false; + mShowingAutoCorrectionInverted = false; removeAllViews(); } @@ -236,8 +321,7 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo previewPopup.showAtLocation(this, Gravity.NO_GRAVITY, posX, posY); } previewText.setVisibility(VISIBLE); - mHandler.sendMessageDelayed( - mHandler.obtainMessage(MSG_HIDE_PREVIEW), DELAY_HIDE_PREVIEW); + mHandler.postHidePreview(); } private void addToDictionary(CharSequence word) { @@ -273,7 +357,7 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo @Override public void onDetachedFromWindow() { super.onDetachedFromWindow(); - mHandler.removeMessages(MSG_HIDE_PREVIEW); + mHandler.cancelAllMessages(); hidePreview(); } } diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 16a369a9e..ed5ce6bb8 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -81,10 +81,8 @@ import java.util.Locale; /** * Input method implementation for Qwerty'ish keyboard. */ -public class LatinIME extends InputMethodService - implements KeyboardActionListener, - SharedPreferences.OnSharedPreferenceChangeListener, - Tutorial.TutorialListener { +public class LatinIME extends InputMethodService implements KeyboardActionListener, + SharedPreferences.OnSharedPreferenceChangeListener, Tutorial.TutorialListener { private static final String TAG = "LatinIME"; private static final boolean PERF_DEBUG = false; private static final boolean DEBUG = false; @@ -1167,9 +1165,7 @@ public class LatinIME extends InputMethodService if (ic == null) return; abortCorrection(false); ic.beginBatchEdit(); - if (mPredicting) { - commitTyped(ic); - } + commitTyped(ic); maybeRemovePreviousPeriod(text); ic.commitText(text, 1); ic.endBatchEdit(); @@ -1382,7 +1378,14 @@ public class LatinIME extends InputMethodService doubleSpace(); } 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(); if (ic != null) { @@ -1564,7 +1567,7 @@ public class LatinIME extends InputMethodService if (mBestWord != null && mBestWord.length() > 0) { TextEntryState.acceptedDefault(mWord.getTypedWord(), mBestWord); mJustAccepted = true; - pickSuggestion(mBestWord, false); + pickSuggestion(mBestWord); // Add the word to the auto dictionary if it's not a known word addToDictionaries(mBestWord, AutoDictionary.FREQUENCY_FOR_TYPED); return true; @@ -1615,7 +1618,7 @@ public class LatinIME extends InputMethodService return; } mJustAccepted = true; - pickSuggestion(suggestion, correcting); + pickSuggestion(suggestion); // Add the word to the auto dictionary if it's not a known word if (index == 0) { addToDictionaries(suggestion, AutoDictionary.FREQUENCY_FOR_PICKED); @@ -1660,10 +1663,8 @@ public class LatinIME extends InputMethodService * retrieval. * @param suggestion the suggestion picked by the user to be committed to * 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; if (!switcher.isKeyboardAvailable()) return; @@ -1676,11 +1677,6 @@ public class LatinIME extends InputMethodService mPredicting = false; mCommittedLength = suggestion.length(); switcher.setPreferredLetters(null); - // If we just corrected a word, then don't show punctuations - if (!correcting) { - setPunctuationSuggestions(); - } - switcher.updateShiftState(); } /**