SuggestionStripView.java revision 6f7218627eda110a8454053f8ecb7b80edfdc8ce
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 196f7218627eda110a8454053f8ecb7b80edfdc8cesatokimport com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; 206f7218627eda110a8454053f8ecb7b80edfdc8cesatok 21923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.Context; 2266a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasaniimport android.content.res.Resources; 236f7218627eda110a8454053f8ecb7b80edfdc8cesatokimport android.graphics.Color; 24923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.graphics.Typeface; 25e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaokaimport android.os.Handler; 26e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaokaimport android.os.Message; 27522d5c16d20657e7d26009fe9c067404e16a6c2aTadashi G. Takaokaimport android.text.Spannable; 28522d5c16d20657e7d26009fe9c067404e16a6c2aTadashi G. Takaokaimport android.text.SpannableString; 29e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaokaimport android.text.Spanned; 30e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaokaimport android.text.TextUtils; 3155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaokaimport android.text.style.BackgroundColorSpan; 32522d5c16d20657e7d26009fe9c067404e16a6c2aTadashi G. Takaokaimport android.text.style.CharacterStyle; 3355b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaokaimport android.text.style.ForegroundColorSpan; 34522d5c16d20657e7d26009fe9c067404e16a6c2aTadashi G. Takaokaimport android.text.style.StyleSpan; 35522d5c16d20657e7d26009fe9c067404e16a6c2aTadashi G. Takaokaimport android.text.style.UnderlineSpan; 36923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.util.AttributeSet; 37923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.Gravity; 38923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.LayoutInflater; 39923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.View; 40e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaokaimport android.view.View.OnClickListener; 41e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaokaimport android.view.View.OnLongClickListener; 42e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaokaimport android.view.ViewGroup; 43e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaokaimport android.widget.ImageView; 44e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaokaimport android.widget.LinearLayout; 45923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.widget.PopupWindow; 46923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.widget.TextView; 47923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 48179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaokaimport java.util.ArrayList; 496f7218627eda110a8454053f8ecb7b80edfdc8cesatokimport java.util.List; 50179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaoka 51e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaokapublic class CandidateView extends LinearLayout implements OnClickListener, OnLongClickListener { 52923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 5382411d47ba7e8133ed2390c6920945e139a738cesatok private static final CharacterStyle BOLD_SPAN = new StyleSpan(Typeface.BOLD); 5482411d47ba7e8133ed2390c6920945e139a738cesatok private static final CharacterStyle UNDERLINE_SPAN = new UnderlineSpan(); 55e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka private static final int MAX_SUGGESTIONS = 16; 56923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 576f7218627eda110a8454053f8ecb7b80edfdc8cesatok private static boolean DBG = LatinImeLogger.sDBG; 586f7218627eda110a8454053f8ecb7b80edfdc8cesatok 5982411d47ba7e8133ed2390c6920945e139a738cesatok private final ArrayList<View> mWords = new ArrayList<View>(); 60e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka private final boolean mConfigCandidateHighlightFontColorEnabled; 6182411d47ba7e8133ed2390c6920945e139a738cesatok private final CharacterStyle mInvertedForegroundColorSpan; 6282411d47ba7e8133ed2390c6920945e139a738cesatok private final CharacterStyle mInvertedBackgroundColorSpan; 63179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaoka private final int mColorNormal; 64179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaoka private final int mColorRecommended; 65179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaoka private final int mColorOther; 6682411d47ba7e8133ed2390c6920945e139a738cesatok private final PopupWindow mPreviewPopup; 6782411d47ba7e8133ed2390c6920945e139a738cesatok private final TextView mPreviewText; 6866a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani 6982411d47ba7e8133ed2390c6920945e139a738cesatok private LatinIME mService; 707e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka private SuggestedWords mSuggestions = SuggestedWords.EMPTY; 7155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka private boolean mShowingAutoCorrectionInverted; 72e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka private boolean mShowingAddToDictionary; 736a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani 7455b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka private final UiHandler mHandler = new UiHandler(); 7555b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 7655b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka private class UiHandler extends Handler { 7755b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka private static final int MSG_HIDE_PREVIEW = 0; 7855b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka private static final int MSG_UPDATE_SUGGESTION = 1; 7955b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 8055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka private static final long DELAY_HIDE_PREVIEW = 1000; 8155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka private static final long DELAY_UPDATE_SUGGESTION = 300; 8255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 83e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka @Override 84e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka public void dispatchMessage(Message msg) { 85e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka switch (msg.what) { 86e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka case MSG_HIDE_PREVIEW: 87e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka hidePreview(); 88e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka break; 8955b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka case MSG_UPDATE_SUGGESTION: 909fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka updateSuggestions(); 9155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka break; 92e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka } 93e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka } 9455b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 9555b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka public void postHidePreview() { 9655b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka cancelHidePreview(); 9755b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka sendMessageDelayed(obtainMessage(MSG_HIDE_PREVIEW), DELAY_HIDE_PREVIEW); 9855b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka } 9955b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 10055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka public void cancelHidePreview() { 10155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka removeMessages(MSG_HIDE_PREVIEW); 10255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka } 10355b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 1049fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka public void postUpdateSuggestions() { 10555b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka cancelUpdateSuggestions(); 1069fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka sendMessageDelayed(obtainMessage(MSG_UPDATE_SUGGESTION), 10755b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka DELAY_UPDATE_SUGGESTION); 10855b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka } 10955b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 11055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka public void cancelUpdateSuggestions() { 11155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka removeMessages(MSG_UPDATE_SUGGESTION); 11255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka } 11355b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 11455b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka public void cancelAllMessages() { 11555b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka cancelHidePreview(); 11655b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka cancelUpdateSuggestions(); 11755b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka } 118e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka } 119179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaoka 120923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 121923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Construct a CandidateView for showing suggested words for completion. 122923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * @param context 123923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * @param attrs 124923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 125923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public CandidateView(Context context, AttributeSet attrs) { 126923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project super(context, attrs); 127923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 12866a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani Resources res = context.getResources(); 129923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project mPreviewPopup = new PopupWindow(context); 130e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka LayoutInflater inflater = LayoutInflater.from(context); 131e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka mPreviewText = (TextView) inflater.inflate(R.layout.candidate_preview, null); 132e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka mPreviewPopup.setWindowLayoutMode(ViewGroup.LayoutParams.WRAP_CONTENT, 133e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka ViewGroup.LayoutParams.WRAP_CONTENT); 134923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project mPreviewPopup.setContentView(mPreviewText); 135923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project mPreviewPopup.setBackgroundDrawable(null); 136179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaoka mPreviewPopup.setAnimationStyle(R.style.KeyPreviewAnimation); 137e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka mConfigCandidateHighlightFontColorEnabled = 138e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka res.getBoolean(R.bool.config_candidate_highlight_font_color_enabled); 13966a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani mColorNormal = res.getColor(R.color.candidate_normal); 14066a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani mColorRecommended = res.getColor(R.color.candidate_recommended); 14166a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani mColorOther = res.getColor(R.color.candidate_other); 14255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka mInvertedForegroundColorSpan = new ForegroundColorSpan(mColorNormal ^ 0x00ffffff); 14355b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka mInvertedBackgroundColorSpan = new BackgroundColorSpan(mColorNormal); 144923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 145e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka for (int i = 0; i < MAX_SUGGESTIONS; i++) { 146e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka View v = inflater.inflate(R.layout.candidate, null); 147e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka TextView tv = (TextView)v.findViewById(R.id.candidate_word); 148e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka tv.setTag(i); 149e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka tv.setOnClickListener(this); 150e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka if (i == 0) 151e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka tv.setOnLongClickListener(this); 152e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka ImageView divider = (ImageView)v.findViewById(R.id.candidate_divider); 153e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka // Do not display divider of first candidate. 1547e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka divider.setVisibility(i == 0 ? GONE : VISIBLE); 155e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka mWords.add(v); 156c9716b28ce438e06b5cacc07fc002944bcbe24a0Tadashi G. Takaoka } 157179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaoka 158e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka scrollTo(0, getScrollY()); 159923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 160c9716b28ce438e06b5cacc07fc002944bcbe24a0Tadashi G. Takaoka 161923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 162923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * A connection back to the service to communicate with the text field 163923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * @param listener 164923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 165923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public void setService(LatinIME listener) { 166923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project mService = listener; 167923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 168923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 1697e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka public void setSuggestions(SuggestedWords suggestions) { 1709fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka if (suggestions == null) 171a15e45ef45931ba46678b39c159518d8aa2d4d65Tadashi G. Takaoka return; 1729fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka mSuggestions = suggestions; 17355b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka if (mShowingAutoCorrectionInverted) { 1749fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka mHandler.postUpdateSuggestions(); 17555b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka } else { 1769fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka updateSuggestions(); 17755b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka } 17855b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka } 17955b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 1809fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka private void updateSuggestions() { 1819fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka final SuggestedWords suggestions = mSuggestions; 182e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka clear(); 1837e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka final int count = suggestions.size(); 184923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project for (int i = 0; i < count; i++) { 1857e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka CharSequence word = suggestions.getWord(i); 1867e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka if (word == null) continue; 1877e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka final int wordLength = word.length(); 1886f7218627eda110a8454053f8ecb7b80edfdc8cesatok final List<SuggestedWordInfo> suggestedWordInfoList = 1896f7218627eda110a8454053f8ecb7b80edfdc8cesatok suggestions.mSuggestedWordInfoList; 190179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaoka 19155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka final View v = mWords.get(i); 19255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka final TextView tv = (TextView)v.findViewById(R.id.candidate_word); 1937e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka final TextView dv = (TextView)v.findViewById(R.id.candidate_debug_info); 194e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka tv.setTextColor(mColorNormal); 19582411d47ba7e8133ed2390c6920945e139a738cesatok // TODO: Needs safety net? 1967e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka if (suggestions.mHasMinimalSuggestion 19782411d47ba7e8133ed2390c6920945e139a738cesatok && ((i == 1 && !suggestions.mTypedWordValid) 19882411d47ba7e8133ed2390c6920945e139a738cesatok || (i == 0 && suggestions.mTypedWordValid))) { 1998ec36be4f5d7f85a658235ccfeb9c6cb424ddb2aTadashi G. Takaoka final CharacterStyle style; 200522d5c16d20657e7d26009fe9c067404e16a6c2aTadashi G. Takaoka if (mConfigCandidateHighlightFontColorEnabled) { 2018ec36be4f5d7f85a658235ccfeb9c6cb424ddb2aTadashi G. Takaoka style = BOLD_SPAN; 202e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka tv.setTextColor(mColorRecommended); 203522d5c16d20657e7d26009fe9c067404e16a6c2aTadashi G. Takaoka } else { 2048ec36be4f5d7f85a658235ccfeb9c6cb424ddb2aTadashi G. Takaoka style = UNDERLINE_SPAN; 205522d5c16d20657e7d26009fe9c067404e16a6c2aTadashi G. Takaoka } 2067e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka final Spannable spannedWord = new SpannableString(word); 2077e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka spannedWord.setSpan(style, 0, wordLength, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); 2087e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka word = spannedWord; 20989c58745d639a4434dfbe600c28dad1bc8bc6888Tadashi G. Takaoka } else if (i != 0 || (wordLength == 1 && count > 1)) { 21089c58745d639a4434dfbe600c28dad1bc8bc6888Tadashi G. Takaoka // HACK: even if i == 0, we use mColorOther when this 21189c58745d639a4434dfbe600c28dad1bc8bc6888Tadashi G. Takaoka // suggestion's length is 1 21289c58745d639a4434dfbe600c28dad1bc8bc6888Tadashi G. Takaoka // and there are multiple suggestions, such as the default 21389c58745d639a4434dfbe600c28dad1bc8bc6888Tadashi G. Takaoka // punctuation list. 21489c58745d639a4434dfbe600c28dad1bc8bc6888Tadashi G. Takaoka if (mConfigCandidateHighlightFontColorEnabled) 215e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka tv.setTextColor(mColorOther); 216179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaoka } 2177e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka tv.setText(word); 218e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka tv.setClickable(true); 2196f7218627eda110a8454053f8ecb7b80edfdc8cesatok 2206f7218627eda110a8454053f8ecb7b80edfdc8cesatok if (suggestedWordInfoList != null && suggestedWordInfoList.get(i) != null) { 2216f7218627eda110a8454053f8ecb7b80edfdc8cesatok final SuggestedWordInfo info = suggestedWordInfoList.get(i); 2226f7218627eda110a8454053f8ecb7b80edfdc8cesatok if (info.isPreviousSuggestedWord()) { 2236f7218627eda110a8454053f8ecb7b80edfdc8cesatok int color = tv.getCurrentTextColor(); 2246f7218627eda110a8454053f8ecb7b80edfdc8cesatok tv.setTextColor(Color.argb((int)(Color.alpha(color) * 0.5f), Color.red(color), 2256f7218627eda110a8454053f8ecb7b80edfdc8cesatok Color.green(color), Color.blue(color))); 2266f7218627eda110a8454053f8ecb7b80edfdc8cesatok } 2276f7218627eda110a8454053f8ecb7b80edfdc8cesatok final String debugString = info.getDebugString(); 2286f7218627eda110a8454053f8ecb7b80edfdc8cesatok if (DBG) { 2296f7218627eda110a8454053f8ecb7b80edfdc8cesatok if (!TextUtils.isEmpty(debugString)) { 2306f7218627eda110a8454053f8ecb7b80edfdc8cesatok dv.setText(debugString); 2316f7218627eda110a8454053f8ecb7b80edfdc8cesatok dv.setVisibility(VISIBLE); 2326f7218627eda110a8454053f8ecb7b80edfdc8cesatok } 2336f7218627eda110a8454053f8ecb7b80edfdc8cesatok } 2347e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka } else { 2357e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka dv.setVisibility(GONE); 2367e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka } 237e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka addView(v); 238923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 239e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka 2407a722cbfc8bbb8a7b260895266a0fd3a9baf1994Amith Yamasani scrollTo(0, getScrollY()); 241923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project requestLayout(); 242923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 243923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 24455b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka public void onAutoCorrectionInverted(CharSequence autoCorrectedWord) { 24555b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka // Displaying auto corrected word as inverted is enabled only when highlighting candidate 24655b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka // with color is disabled. 24755b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka if (mConfigCandidateHighlightFontColorEnabled) 24855b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka return; 24955b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka final TextView tv = (TextView)mWords.get(1).findViewById(R.id.candidate_word); 25055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka final Spannable word = new SpannableString(autoCorrectedWord); 25155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka final int wordLength = word.length(); 252e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka word.setSpan(mInvertedBackgroundColorSpan, 0, wordLength, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); 253e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka word.setSpan(mInvertedForegroundColorSpan, 0, wordLength, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); 25455b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka tv.setText(word); 25555b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka mShowingAutoCorrectionInverted = true; 25655b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka } 25755b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 2587e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka public boolean isConfigCandidateHighlightFontColorEnabled() { 2597e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka return mConfigCandidateHighlightFontColorEnabled; 2607e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka } 2617e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka 262b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani public boolean isShowingAddToDictionaryHint() { 263b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani return mShowingAddToDictionary; 264b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani } 265b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani 26666a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani public void showAddToDictionaryHint(CharSequence word) { 2677e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka SuggestedWords.Builder builder = new SuggestedWords.Builder() 2687e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka .addWord(word) 2697e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka .addWord(getContext().getText(R.string.hint_add_to_dictionary)); 2707e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka setSuggestions(builder.build()); 27166a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani mShowingAddToDictionary = true; 272e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka // Disable R.string.hint_add_to_dictionary button 273e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka TextView tv = (TextView)getChildAt(1).findViewById(R.id.candidate_word); 274e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka tv.setClickable(false); 27566a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani } 27666a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani 2776558253160e2039c87f424bd814f402ecd31de3bKen Wakasa public boolean dismissAddToDictionaryHint() { 2786558253160e2039c87f424bd814f402ecd31de3bKen Wakasa if (!mShowingAddToDictionary) return false; 2796558253160e2039c87f424bd814f402ecd31de3bKen Wakasa clear(); 2806558253160e2039c87f424bd814f402ecd31de3bKen Wakasa return true; 2816558253160e2039c87f424bd814f402ecd31de3bKen Wakasa } 2826558253160e2039c87f424bd814f402ecd31de3bKen Wakasa 2837e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka public SuggestedWords getSuggestions() { 284979f8690967ff5409fe18f5085858ccdb8e0ccf1satok return mSuggestions; 285979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 286979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 287923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public void clear() { 28866a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani mShowingAddToDictionary = false; 28955b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka mShowingAutoCorrectionInverted = false; 290e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka removeAllViews(); 291923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 292923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 2936ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani private void hidePreview() { 294179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaoka mPreviewPopup.dismiss(); 2956ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani } 296e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka 297e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka private void showPreview(int index, CharSequence word) { 298e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka if (TextUtils.isEmpty(word)) 299e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka return; 300e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka 301e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka final TextView previewText = mPreviewText; 302e9311bc893c71f2a016d67ddb6b6234661e8a4f6Tadashi G. Takaoka previewText.setTextColor(mColorNormal); 303e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka previewText.setText(word); 304e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka previewText.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), 305e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); 306e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka View v = getChildAt(index); 307e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka final int[] offsetInWindow = new int[2]; 308e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka v.getLocationInWindow(offsetInWindow); 309e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka final int posX = offsetInWindow[0]; 310e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka final int posY = offsetInWindow[1] - previewText.getMeasuredHeight(); 311e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka final PopupWindow previewPopup = mPreviewPopup; 312e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka if (previewPopup.isShowing()) { 313e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka previewPopup.update(posX, posY, previewPopup.getWidth(), previewPopup.getHeight()); 314e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka } else { 315e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka previewPopup.showAtLocation(this, Gravity.NO_GRAVITY, posX, posY); 316923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 317e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka previewText.setVisibility(VISIBLE); 31855b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka mHandler.postHidePreview(); 319923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 320fcba53ef7c874a4685c12c01404c91b779cae1e8Tadashi G. Takaoka 321e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka private void addToDictionary(CharSequence word) { 322923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project if (mService.addWordToDictionary(word.toString())) { 323e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka showPreview(0, getContext().getString(R.string.added_word, word)); 324e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka } 325e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka } 326e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka 327e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka @Override 328e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka public boolean onLongClick(View view) { 329e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka int index = (Integer) view.getTag(); 3307e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka CharSequence word = mSuggestions.getWord(index); 331e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka if (word.length() < 2) 332e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka return false; 333e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka addToDictionary(word); 334e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka return true; 335e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka } 336e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka 337e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka @Override 338e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka public void onClick(View view) { 339e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka int index = (Integer) view.getTag(); 3407e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka CharSequence word = mSuggestions.getWord(index); 341e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka if (mShowingAddToDictionary && index == 0) { 342e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka addToDictionary(word); 343e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka } else { 3447e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka if (!mSuggestions.mIsApplicationSpecifiedCompletions) { 3457e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka TextEntryState.acceptedSuggestion(mSuggestions.getWord(0), word); 346e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka } 347e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka mService.pickSuggestionManually(index, word); 348923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 349923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 35082411d47ba7e8133ed2390c6920945e139a738cesatok 3516ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani @Override 3526ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani public void onDetachedFromWindow() { 3536ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani super.onDetachedFromWindow(); 35455b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka mHandler.cancelAllMessages(); 3556ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani hidePreview(); 3566ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani } 357923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project} 358