SuggestionStripView.java revision 82411d47ba7e8133ed2390c6920945e139a738ce
1923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project/* 2e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka * Copyright (C) 2010 The Android Open Source Project 3e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka * 4923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * use this file except in compliance with the License. You may obtain a copy of 6923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * the License at 7e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka * 8923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 9e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka * 10923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 11923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * License for the specific language governing permissions and limitations under 14923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * the License. 15923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 16923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 17923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectpackage com.android.inputmethod.latin; 18923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 19923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.Context; 2066a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasaniimport android.content.res.Resources; 21923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.graphics.Typeface; 22e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaokaimport android.os.Handler; 23e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaokaimport android.os.Message; 24522d5c16d20657e7d26009fe9c067404e16a6c2aTadashi G. Takaokaimport android.text.Spannable; 25522d5c16d20657e7d26009fe9c067404e16a6c2aTadashi G. Takaokaimport android.text.SpannableString; 26e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaokaimport android.text.Spanned; 27e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaokaimport android.text.TextUtils; 2855b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaokaimport android.text.style.BackgroundColorSpan; 29522d5c16d20657e7d26009fe9c067404e16a6c2aTadashi G. Takaokaimport android.text.style.CharacterStyle; 3055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaokaimport android.text.style.ForegroundColorSpan; 31522d5c16d20657e7d26009fe9c067404e16a6c2aTadashi G. Takaokaimport android.text.style.StyleSpan; 32522d5c16d20657e7d26009fe9c067404e16a6c2aTadashi G. Takaokaimport android.text.style.UnderlineSpan; 33923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.util.AttributeSet; 34923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.Gravity; 35923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.LayoutInflater; 36923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.View; 37e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaokaimport android.view.View.OnClickListener; 38e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaokaimport android.view.View.OnLongClickListener; 39e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaokaimport android.view.ViewGroup; 40e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaokaimport android.widget.ImageView; 41e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaokaimport android.widget.LinearLayout; 42923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.widget.PopupWindow; 43923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.widget.TextView; 44923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 45179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaokaimport java.util.ArrayList; 46179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaoka 47e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaokapublic class CandidateView extends LinearLayout implements OnClickListener, OnLongClickListener { 48923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 4982411d47ba7e8133ed2390c6920945e139a738cesatok private static final CharacterStyle BOLD_SPAN = new StyleSpan(Typeface.BOLD); 5082411d47ba7e8133ed2390c6920945e139a738cesatok private static final CharacterStyle UNDERLINE_SPAN = new UnderlineSpan(); 51e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka private static final int MAX_SUGGESTIONS = 16; 52923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 5382411d47ba7e8133ed2390c6920945e139a738cesatok private final ArrayList<View> mWords = new ArrayList<View>(); 54e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka private final boolean mConfigCandidateHighlightFontColorEnabled; 5582411d47ba7e8133ed2390c6920945e139a738cesatok private final CharacterStyle mInvertedForegroundColorSpan; 5682411d47ba7e8133ed2390c6920945e139a738cesatok private final CharacterStyle mInvertedBackgroundColorSpan; 57179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaoka private final int mColorNormal; 58179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaoka private final int mColorRecommended; 59179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaoka private final int mColorOther; 6082411d47ba7e8133ed2390c6920945e139a738cesatok private final PopupWindow mPreviewPopup; 6182411d47ba7e8133ed2390c6920945e139a738cesatok private final TextView mPreviewText; 6266a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani 6382411d47ba7e8133ed2390c6920945e139a738cesatok private LatinIME mService; 647e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka private SuggestedWords mSuggestions = SuggestedWords.EMPTY; 6555b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka private boolean mShowingAutoCorrectionInverted; 66e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka private boolean mShowingAddToDictionary; 676a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani 6855b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka private final UiHandler mHandler = new UiHandler(); 6955b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 7055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka private class UiHandler extends Handler { 7155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka private static final int MSG_HIDE_PREVIEW = 0; 7255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka private static final int MSG_UPDATE_SUGGESTION = 1; 7355b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 7455b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka private static final long DELAY_HIDE_PREVIEW = 1000; 7555b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka private static final long DELAY_UPDATE_SUGGESTION = 300; 7655b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 77e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka @Override 78e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka public void dispatchMessage(Message msg) { 79e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka switch (msg.what) { 80e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka case MSG_HIDE_PREVIEW: 81e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka hidePreview(); 82e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka break; 8355b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka case MSG_UPDATE_SUGGESTION: 849fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka updateSuggestions(); 8555b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka break; 86e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka } 87e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka } 8855b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 8955b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka public void postHidePreview() { 9055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka cancelHidePreview(); 9155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka sendMessageDelayed(obtainMessage(MSG_HIDE_PREVIEW), DELAY_HIDE_PREVIEW); 9255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka } 9355b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 9455b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka public void cancelHidePreview() { 9555b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka removeMessages(MSG_HIDE_PREVIEW); 9655b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka } 9755b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 989fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka public void postUpdateSuggestions() { 9955b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka cancelUpdateSuggestions(); 1009fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka sendMessageDelayed(obtainMessage(MSG_UPDATE_SUGGESTION), 10155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka DELAY_UPDATE_SUGGESTION); 10255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka } 10355b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 10455b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka public void cancelUpdateSuggestions() { 10555b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka removeMessages(MSG_UPDATE_SUGGESTION); 10655b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka } 10755b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 10855b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka public void cancelAllMessages() { 10955b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka cancelHidePreview(); 11055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka cancelUpdateSuggestions(); 11155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka } 112e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka } 113179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaoka 114923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 115923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Construct a CandidateView for showing suggested words for completion. 116923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * @param context 117923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * @param attrs 118923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 119923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public CandidateView(Context context, AttributeSet attrs) { 120923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project super(context, attrs); 121923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 12266a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani Resources res = context.getResources(); 123923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project mPreviewPopup = new PopupWindow(context); 124e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka LayoutInflater inflater = LayoutInflater.from(context); 125e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka mPreviewText = (TextView) inflater.inflate(R.layout.candidate_preview, null); 126e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka mPreviewPopup.setWindowLayoutMode(ViewGroup.LayoutParams.WRAP_CONTENT, 127e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka ViewGroup.LayoutParams.WRAP_CONTENT); 128923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project mPreviewPopup.setContentView(mPreviewText); 129923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project mPreviewPopup.setBackgroundDrawable(null); 130179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaoka mPreviewPopup.setAnimationStyle(R.style.KeyPreviewAnimation); 131e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka mConfigCandidateHighlightFontColorEnabled = 132e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka res.getBoolean(R.bool.config_candidate_highlight_font_color_enabled); 13366a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani mColorNormal = res.getColor(R.color.candidate_normal); 13466a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani mColorRecommended = res.getColor(R.color.candidate_recommended); 13566a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani mColorOther = res.getColor(R.color.candidate_other); 13655b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka mInvertedForegroundColorSpan = new ForegroundColorSpan(mColorNormal ^ 0x00ffffff); 13755b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka mInvertedBackgroundColorSpan = new BackgroundColorSpan(mColorNormal); 138923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 139e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka for (int i = 0; i < MAX_SUGGESTIONS; i++) { 140e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka View v = inflater.inflate(R.layout.candidate, null); 141e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka TextView tv = (TextView)v.findViewById(R.id.candidate_word); 142e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka tv.setTag(i); 143e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka tv.setOnClickListener(this); 144e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka if (i == 0) 145e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka tv.setOnLongClickListener(this); 146e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka ImageView divider = (ImageView)v.findViewById(R.id.candidate_divider); 147e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka // Do not display divider of first candidate. 1487e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka divider.setVisibility(i == 0 ? GONE : VISIBLE); 149e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka mWords.add(v); 150c9716b28ce438e06b5cacc07fc002944bcbe24a0Tadashi G. Takaoka } 151179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaoka 152e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka scrollTo(0, getScrollY()); 153923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 154c9716b28ce438e06b5cacc07fc002944bcbe24a0Tadashi G. Takaoka 155923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 156923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * A connection back to the service to communicate with the text field 157923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * @param listener 158923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 159923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public void setService(LatinIME listener) { 160923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project mService = listener; 161923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 162923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 1637e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka public void setSuggestions(SuggestedWords suggestions) { 1649fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka if (suggestions == null) 165a15e45ef45931ba46678b39c159518d8aa2d4d65Tadashi G. Takaoka return; 1669fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka mSuggestions = suggestions; 16755b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka if (mShowingAutoCorrectionInverted) { 1689fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka mHandler.postUpdateSuggestions(); 16955b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka } else { 1709fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka updateSuggestions(); 17155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka } 17255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka } 17355b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 1749fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka private void updateSuggestions() { 1759fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka final SuggestedWords suggestions = mSuggestions; 176e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka clear(); 1777e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka final int count = suggestions.size(); 1787e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka final Object[] debugInfo = suggestions.mDebugInfo; 179923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project for (int i = 0; i < count; i++) { 1807e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka CharSequence word = suggestions.getWord(i); 1817e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka if (word == null) continue; 1827e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka final int wordLength = word.length(); 183179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaoka 18455b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka final View v = mWords.get(i); 18555b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka final TextView tv = (TextView)v.findViewById(R.id.candidate_word); 1867e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka final TextView dv = (TextView)v.findViewById(R.id.candidate_debug_info); 187e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka tv.setTextColor(mColorNormal); 18882411d47ba7e8133ed2390c6920945e139a738cesatok // TODO: Needs safety net? 1897e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka if (suggestions.mHasMinimalSuggestion 19082411d47ba7e8133ed2390c6920945e139a738cesatok && ((i == 1 && !suggestions.mTypedWordValid) 19182411d47ba7e8133ed2390c6920945e139a738cesatok || (i == 0 && suggestions.mTypedWordValid))) { 1928ec36be4f5d7f85a658235ccfeb9c6cb424ddb2aTadashi G. Takaoka final CharacterStyle style; 193522d5c16d20657e7d26009fe9c067404e16a6c2aTadashi G. Takaoka if (mConfigCandidateHighlightFontColorEnabled) { 1948ec36be4f5d7f85a658235ccfeb9c6cb424ddb2aTadashi G. Takaoka style = BOLD_SPAN; 195e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka tv.setTextColor(mColorRecommended); 196522d5c16d20657e7d26009fe9c067404e16a6c2aTadashi G. Takaoka } else { 1978ec36be4f5d7f85a658235ccfeb9c6cb424ddb2aTadashi G. Takaoka style = UNDERLINE_SPAN; 198522d5c16d20657e7d26009fe9c067404e16a6c2aTadashi G. Takaoka } 1997e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka final Spannable spannedWord = new SpannableString(word); 2007e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka spannedWord.setSpan(style, 0, wordLength, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); 2017e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka word = spannedWord; 20289c58745d639a4434dfbe600c28dad1bc8bc6888Tadashi G. Takaoka } else if (i != 0 || (wordLength == 1 && count > 1)) { 20389c58745d639a4434dfbe600c28dad1bc8bc6888Tadashi G. Takaoka // HACK: even if i == 0, we use mColorOther when this 20489c58745d639a4434dfbe600c28dad1bc8bc6888Tadashi G. Takaoka // suggestion's length is 1 20589c58745d639a4434dfbe600c28dad1bc8bc6888Tadashi G. Takaoka // and there are multiple suggestions, such as the default 20689c58745d639a4434dfbe600c28dad1bc8bc6888Tadashi G. Takaoka // punctuation list. 20789c58745d639a4434dfbe600c28dad1bc8bc6888Tadashi G. Takaoka if (mConfigCandidateHighlightFontColorEnabled) 208e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka tv.setTextColor(mColorOther); 209179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaoka } 2107e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka tv.setText(word); 211e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka tv.setClickable(true); 2127e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka if (debugInfo != null && i < debugInfo.length && debugInfo[i] != null 2137e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka && !TextUtils.isEmpty(debugInfo[i].toString())) { 2147e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka dv.setText(debugInfo[i].toString()); 2157e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka dv.setVisibility(VISIBLE); 2167e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka } else { 2177e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka dv.setVisibility(GONE); 2187e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka } 219e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka addView(v); 220923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 221e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka 2227a722cbfc8bbb8a7b260895266a0fd3a9baf1994Amith Yamasani scrollTo(0, getScrollY()); 223923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project requestLayout(); 224923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 225923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 22655b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka public void onAutoCorrectionInverted(CharSequence autoCorrectedWord) { 22755b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka // Displaying auto corrected word as inverted is enabled only when highlighting candidate 22855b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka // with color is disabled. 22955b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka if (mConfigCandidateHighlightFontColorEnabled) 23055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka return; 23155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka final TextView tv = (TextView)mWords.get(1).findViewById(R.id.candidate_word); 23255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka final Spannable word = new SpannableString(autoCorrectedWord); 23355b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka final int wordLength = word.length(); 234e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka word.setSpan(mInvertedBackgroundColorSpan, 0, wordLength, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); 235e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka word.setSpan(mInvertedForegroundColorSpan, 0, wordLength, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); 23655b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka tv.setText(word); 23755b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka mShowingAutoCorrectionInverted = true; 23855b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka } 23955b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 2407e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka public boolean isConfigCandidateHighlightFontColorEnabled() { 2417e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka return mConfigCandidateHighlightFontColorEnabled; 2427e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka } 2437e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka 244b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani public boolean isShowingAddToDictionaryHint() { 245b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani return mShowingAddToDictionary; 246b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani } 247b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani 24866a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani public void showAddToDictionaryHint(CharSequence word) { 2497e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka SuggestedWords.Builder builder = new SuggestedWords.Builder() 2507e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka .addWord(word) 2517e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka .addWord(getContext().getText(R.string.hint_add_to_dictionary)); 2527e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka setSuggestions(builder.build()); 25366a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani mShowingAddToDictionary = true; 254e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka // Disable R.string.hint_add_to_dictionary button 255e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka TextView tv = (TextView)getChildAt(1).findViewById(R.id.candidate_word); 256e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka tv.setClickable(false); 25766a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani } 25866a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani 2596558253160e2039c87f424bd814f402ecd31de3bKen Wakasa public boolean dismissAddToDictionaryHint() { 2606558253160e2039c87f424bd814f402ecd31de3bKen Wakasa if (!mShowingAddToDictionary) return false; 2616558253160e2039c87f424bd814f402ecd31de3bKen Wakasa clear(); 2626558253160e2039c87f424bd814f402ecd31de3bKen Wakasa return true; 2636558253160e2039c87f424bd814f402ecd31de3bKen Wakasa } 2646558253160e2039c87f424bd814f402ecd31de3bKen Wakasa 2657e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka public SuggestedWords getSuggestions() { 266979f8690967ff5409fe18f5085858ccdb8e0ccf1satok return mSuggestions; 267979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 268979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 269923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public void clear() { 27066a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani mShowingAddToDictionary = false; 27155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka mShowingAutoCorrectionInverted = false; 272e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka removeAllViews(); 273923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 274923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 2756ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani private void hidePreview() { 276179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaoka mPreviewPopup.dismiss(); 2776ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani } 278e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka 279e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka private void showPreview(int index, CharSequence word) { 280e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka if (TextUtils.isEmpty(word)) 281e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka return; 282e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka 283e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka final TextView previewText = mPreviewText; 284e9311bc893c71f2a016d67ddb6b6234661e8a4f6Tadashi G. Takaoka previewText.setTextColor(mColorNormal); 285e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka previewText.setText(word); 286e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka previewText.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), 287e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); 288e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka View v = getChildAt(index); 289e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka final int[] offsetInWindow = new int[2]; 290e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka v.getLocationInWindow(offsetInWindow); 291e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka final int posX = offsetInWindow[0]; 292e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka final int posY = offsetInWindow[1] - previewText.getMeasuredHeight(); 293e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka final PopupWindow previewPopup = mPreviewPopup; 294e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka if (previewPopup.isShowing()) { 295e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka previewPopup.update(posX, posY, previewPopup.getWidth(), previewPopup.getHeight()); 296e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka } else { 297e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka previewPopup.showAtLocation(this, Gravity.NO_GRAVITY, posX, posY); 298923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 299e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka previewText.setVisibility(VISIBLE); 30055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka mHandler.postHidePreview(); 301923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 302fcba53ef7c874a4685c12c01404c91b779cae1e8Tadashi G. Takaoka 303e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka private void addToDictionary(CharSequence word) { 304923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project if (mService.addWordToDictionary(word.toString())) { 305e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka showPreview(0, getContext().getString(R.string.added_word, word)); 306e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka } 307e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka } 308e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka 309e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka @Override 310e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka public boolean onLongClick(View view) { 311e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka int index = (Integer) view.getTag(); 3127e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka CharSequence word = mSuggestions.getWord(index); 313e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka if (word.length() < 2) 314e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka return false; 315e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka addToDictionary(word); 316e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka return true; 317e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka } 318e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka 319e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka @Override 320e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka public void onClick(View view) { 321e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka int index = (Integer) view.getTag(); 3227e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka CharSequence word = mSuggestions.getWord(index); 323e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka if (mShowingAddToDictionary && index == 0) { 324e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka addToDictionary(word); 325e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka } else { 3267e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka if (!mSuggestions.mIsApplicationSpecifiedCompletions) { 3277e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka TextEntryState.acceptedSuggestion(mSuggestions.getWord(0), word); 328e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka } 329e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka mService.pickSuggestionManually(index, word); 330923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 331923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 33282411d47ba7e8133ed2390c6920945e139a738cesatok 3336ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani @Override 3346ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani public void onDetachedFromWindow() { 3356ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani super.onDetachedFromWindow(); 33655b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka mHandler.cancelAllMessages(); 3376ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani hidePreview(); 3386ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani } 339923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project} 340