SuggestionStripView.java revision c97810693dfe83bf37c09f73c8d4b40f2ba8dddb
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; 216f7218627eda110a8454053f8ecb7b80edfdc8cesatokimport android.graphics.Color; 22923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.graphics.Typeface; 23e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaokaimport android.os.Handler; 24e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaokaimport android.os.Message; 25522d5c16d20657e7d26009fe9c067404e16a6c2aTadashi G. Takaokaimport android.text.Spannable; 26522d5c16d20657e7d26009fe9c067404e16a6c2aTadashi G. Takaokaimport android.text.SpannableString; 27e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaokaimport android.text.Spanned; 28e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaokaimport android.text.TextUtils; 2955b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaokaimport android.text.style.BackgroundColorSpan; 30522d5c16d20657e7d26009fe9c067404e16a6c2aTadashi G. Takaokaimport android.text.style.CharacterStyle; 3155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaokaimport android.text.style.ForegroundColorSpan; 32522d5c16d20657e7d26009fe9c067404e16a6c2aTadashi G. Takaokaimport android.text.style.StyleSpan; 33522d5c16d20657e7d26009fe9c067404e16a6c2aTadashi G. Takaokaimport android.text.style.UnderlineSpan; 34923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.util.AttributeSet; 35923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.Gravity; 36923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.LayoutInflater; 37923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.View; 38e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaokaimport android.view.View.OnClickListener; 39e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaokaimport android.view.View.OnLongClickListener; 40e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaokaimport android.view.ViewGroup; 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 45ddb61ea461b920d87be4ad78c8a36eec1013b965Tadashi G. Takaokaimport com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; 46ddb61ea461b920d87be4ad78c8a36eec1013b965Tadashi G. Takaoka 47179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaokaimport java.util.ArrayList; 486f7218627eda110a8454053f8ecb7b80edfdc8cesatokimport java.util.List; 49179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaoka 50e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaokapublic class CandidateView extends LinearLayout implements OnClickListener, OnLongClickListener { 51923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 52c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka public interface Listener { 53c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka public boolean addWordToDictionary(String word); 54c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka public void pickSuggestionManually(int index, CharSequence word); 55c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka } 56c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka 5782411d47ba7e8133ed2390c6920945e139a738cesatok private static final CharacterStyle BOLD_SPAN = new StyleSpan(Typeface.BOLD); 5882411d47ba7e8133ed2390c6920945e139a738cesatok private static final CharacterStyle UNDERLINE_SPAN = new UnderlineSpan(); 59e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka private static final int MAX_SUGGESTIONS = 16; 60923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 618553b5ec315660ab53dd9234e64e1e39ea09ec0fJean Chalard private static final boolean DBG = LatinImeLogger.sDBG; 626f7218627eda110a8454053f8ecb7b80edfdc8cesatok 6382411d47ba7e8133ed2390c6920945e139a738cesatok private final ArrayList<View> mWords = new ArrayList<View>(); 64ddb61ea461b920d87be4ad78c8a36eec1013b965Tadashi G. Takaoka private final ArrayList<View> mDividers = new ArrayList<View>(); 65e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka private final boolean mConfigCandidateHighlightFontColorEnabled; 6682411d47ba7e8133ed2390c6920945e139a738cesatok private final CharacterStyle mInvertedForegroundColorSpan; 6782411d47ba7e8133ed2390c6920945e139a738cesatok private final CharacterStyle mInvertedBackgroundColorSpan; 68179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaoka private final int mColorNormal; 69179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaoka private final int mColorRecommended; 70179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaoka private final int mColorOther; 7182411d47ba7e8133ed2390c6920945e139a738cesatok private final PopupWindow mPreviewPopup; 7282411d47ba7e8133ed2390c6920945e139a738cesatok private final TextView mPreviewText; 7366a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani 74c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka private Listener mListener; 757e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka private SuggestedWords mSuggestions = SuggestedWords.EMPTY; 7655b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka private boolean mShowingAutoCorrectionInverted; 77e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka private boolean mShowingAddToDictionary; 786a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani 7955b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka private final UiHandler mHandler = new UiHandler(); 8055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 8155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka private class UiHandler extends Handler { 8255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka private static final int MSG_HIDE_PREVIEW = 0; 8355b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka private static final int MSG_UPDATE_SUGGESTION = 1; 8455b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 8555b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka private static final long DELAY_HIDE_PREVIEW = 1000; 8655b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka private static final long DELAY_UPDATE_SUGGESTION = 300; 8755b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 88e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka @Override 89e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka public void dispatchMessage(Message msg) { 90e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka switch (msg.what) { 91e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka case MSG_HIDE_PREVIEW: 92e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka hidePreview(); 93e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka break; 9455b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka case MSG_UPDATE_SUGGESTION: 959fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka updateSuggestions(); 9655b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka break; 97e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka } 98e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka } 9955b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 10055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka public void postHidePreview() { 10155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka cancelHidePreview(); 10255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka sendMessageDelayed(obtainMessage(MSG_HIDE_PREVIEW), DELAY_HIDE_PREVIEW); 10355b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka } 10455b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 10555b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka public void cancelHidePreview() { 10655b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka removeMessages(MSG_HIDE_PREVIEW); 10755b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka } 10855b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 1099fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka public void postUpdateSuggestions() { 11055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka cancelUpdateSuggestions(); 1119fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka sendMessageDelayed(obtainMessage(MSG_UPDATE_SUGGESTION), 11255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka DELAY_UPDATE_SUGGESTION); 11355b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka } 11455b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 11555b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka public void cancelUpdateSuggestions() { 11655b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka removeMessages(MSG_UPDATE_SUGGESTION); 11755b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka } 11855b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 11955b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka public void cancelAllMessages() { 12055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka cancelHidePreview(); 12155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka cancelUpdateSuggestions(); 12255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka } 123e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka } 124179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaoka 125923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 126923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Construct a CandidateView for showing suggested words for completion. 127923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * @param context 128923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * @param attrs 129923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 130923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public CandidateView(Context context, AttributeSet attrs) { 131923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project super(context, attrs); 132923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 13366a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani Resources res = context.getResources(); 134923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project mPreviewPopup = new PopupWindow(context); 135e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka LayoutInflater inflater = LayoutInflater.from(context); 136e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka mPreviewText = (TextView) inflater.inflate(R.layout.candidate_preview, null); 137e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka mPreviewPopup.setWindowLayoutMode(ViewGroup.LayoutParams.WRAP_CONTENT, 138e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka ViewGroup.LayoutParams.WRAP_CONTENT); 139923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project mPreviewPopup.setContentView(mPreviewText); 140923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project mPreviewPopup.setBackgroundDrawable(null); 141e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka mConfigCandidateHighlightFontColorEnabled = 142e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka res.getBoolean(R.bool.config_candidate_highlight_font_color_enabled); 14366a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani mColorNormal = res.getColor(R.color.candidate_normal); 14466a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani mColorRecommended = res.getColor(R.color.candidate_recommended); 14566a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani mColorOther = res.getColor(R.color.candidate_other); 14655b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka mInvertedForegroundColorSpan = new ForegroundColorSpan(mColorNormal ^ 0x00ffffff); 14755b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka mInvertedBackgroundColorSpan = new BackgroundColorSpan(mColorNormal); 148923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 149e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka for (int i = 0; i < MAX_SUGGESTIONS; i++) { 150e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka View v = inflater.inflate(R.layout.candidate, null); 151e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka TextView tv = (TextView)v.findViewById(R.id.candidate_word); 152e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka tv.setTag(i); 153e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka tv.setOnClickListener(this); 154e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka if (i == 0) 155e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka tv.setOnLongClickListener(this); 156e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka mWords.add(v); 157ddb61ea461b920d87be4ad78c8a36eec1013b965Tadashi G. Takaoka if (i > 0) { 158ddb61ea461b920d87be4ad78c8a36eec1013b965Tadashi G. Takaoka View divider = inflater.inflate(R.layout.candidate_divider, null); 159ddb61ea461b920d87be4ad78c8a36eec1013b965Tadashi G. Takaoka mDividers.add(divider); 160ddb61ea461b920d87be4ad78c8a36eec1013b965Tadashi G. Takaoka } 161c9716b28ce438e06b5cacc07fc002944bcbe24a0Tadashi G. Takaoka } 162179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaoka 163e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka scrollTo(0, getScrollY()); 164923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 165c9716b28ce438e06b5cacc07fc002944bcbe24a0Tadashi G. Takaoka 166923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 167c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka * A connection back to the input method. 168923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * @param listener 169923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 170c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka public void setListener(Listener listener) { 171c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka mListener = listener; 172923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 173923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 1747e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka public void setSuggestions(SuggestedWords suggestions) { 1759fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka if (suggestions == null) 176a15e45ef45931ba46678b39c159518d8aa2d4d65Tadashi G. Takaoka return; 1779fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka mSuggestions = suggestions; 17855b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka if (mShowingAutoCorrectionInverted) { 1799fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka mHandler.postUpdateSuggestions(); 18055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka } else { 1819fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka updateSuggestions(); 18255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka } 18355b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka } 18455b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 1859fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka private void updateSuggestions() { 1869fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka final SuggestedWords suggestions = mSuggestions; 187e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka clear(); 188ec5ae3a1b6ce6d6c87406def849995ec63816c55Ken Wakasa final int count = Math.min(mWords.size(), suggestions.size()); 189923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project for (int i = 0; i < count; i++) { 1907e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka CharSequence word = suggestions.getWord(i); 1917e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka if (word == null) continue; 1927e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka final int wordLength = word.length(); 1936f7218627eda110a8454053f8ecb7b80edfdc8cesatok final List<SuggestedWordInfo> suggestedWordInfoList = 1946f7218627eda110a8454053f8ecb7b80edfdc8cesatok suggestions.mSuggestedWordInfoList; 195179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaoka 19655b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka final View v = mWords.get(i); 19755b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka final TextView tv = (TextView)v.findViewById(R.id.candidate_word); 1987e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka final TextView dv = (TextView)v.findViewById(R.id.candidate_debug_info); 199e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka tv.setTextColor(mColorNormal); 20082411d47ba7e8133ed2390c6920945e139a738cesatok // TODO: Needs safety net? 2017e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka if (suggestions.mHasMinimalSuggestion 20282411d47ba7e8133ed2390c6920945e139a738cesatok && ((i == 1 && !suggestions.mTypedWordValid) 20382411d47ba7e8133ed2390c6920945e139a738cesatok || (i == 0 && suggestions.mTypedWordValid))) { 2048ec36be4f5d7f85a658235ccfeb9c6cb424ddb2aTadashi G. Takaoka final CharacterStyle style; 205522d5c16d20657e7d26009fe9c067404e16a6c2aTadashi G. Takaoka if (mConfigCandidateHighlightFontColorEnabled) { 2068ec36be4f5d7f85a658235ccfeb9c6cb424ddb2aTadashi G. Takaoka style = BOLD_SPAN; 207e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka tv.setTextColor(mColorRecommended); 208522d5c16d20657e7d26009fe9c067404e16a6c2aTadashi G. Takaoka } else { 2098ec36be4f5d7f85a658235ccfeb9c6cb424ddb2aTadashi G. Takaoka style = UNDERLINE_SPAN; 210522d5c16d20657e7d26009fe9c067404e16a6c2aTadashi G. Takaoka } 2117e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka final Spannable spannedWord = new SpannableString(word); 2127e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka spannedWord.setSpan(style, 0, wordLength, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); 2137e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka word = spannedWord; 21489c58745d639a4434dfbe600c28dad1bc8bc6888Tadashi G. Takaoka } else if (i != 0 || (wordLength == 1 && count > 1)) { 21589c58745d639a4434dfbe600c28dad1bc8bc6888Tadashi G. Takaoka // HACK: even if i == 0, we use mColorOther when this 21689c58745d639a4434dfbe600c28dad1bc8bc6888Tadashi G. Takaoka // suggestion's length is 1 21789c58745d639a4434dfbe600c28dad1bc8bc6888Tadashi G. Takaoka // and there are multiple suggestions, such as the default 21889c58745d639a4434dfbe600c28dad1bc8bc6888Tadashi G. Takaoka // punctuation list. 21989c58745d639a4434dfbe600c28dad1bc8bc6888Tadashi G. Takaoka if (mConfigCandidateHighlightFontColorEnabled) 220e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka tv.setTextColor(mColorOther); 221179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaoka } 2227e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka tv.setText(word); 223e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka tv.setClickable(true); 2246f7218627eda110a8454053f8ecb7b80edfdc8cesatok 2256f7218627eda110a8454053f8ecb7b80edfdc8cesatok if (suggestedWordInfoList != null && suggestedWordInfoList.get(i) != null) { 2266f7218627eda110a8454053f8ecb7b80edfdc8cesatok final SuggestedWordInfo info = suggestedWordInfoList.get(i); 2276f7218627eda110a8454053f8ecb7b80edfdc8cesatok if (info.isPreviousSuggestedWord()) { 2286f7218627eda110a8454053f8ecb7b80edfdc8cesatok int color = tv.getCurrentTextColor(); 2296f7218627eda110a8454053f8ecb7b80edfdc8cesatok tv.setTextColor(Color.argb((int)(Color.alpha(color) * 0.5f), Color.red(color), 2306f7218627eda110a8454053f8ecb7b80edfdc8cesatok Color.green(color), Color.blue(color))); 2316f7218627eda110a8454053f8ecb7b80edfdc8cesatok } 2326f7218627eda110a8454053f8ecb7b80edfdc8cesatok final String debugString = info.getDebugString(); 2336f7218627eda110a8454053f8ecb7b80edfdc8cesatok if (DBG) { 2348553b5ec315660ab53dd9234e64e1e39ea09ec0fJean Chalard if (TextUtils.isEmpty(debugString)) { 2358553b5ec315660ab53dd9234e64e1e39ea09ec0fJean Chalard dv.setVisibility(GONE); 2368553b5ec315660ab53dd9234e64e1e39ea09ec0fJean Chalard } else { 2376f7218627eda110a8454053f8ecb7b80edfdc8cesatok dv.setText(debugString); 2386f7218627eda110a8454053f8ecb7b80edfdc8cesatok dv.setVisibility(VISIBLE); 2396f7218627eda110a8454053f8ecb7b80edfdc8cesatok } 2408553b5ec315660ab53dd9234e64e1e39ea09ec0fJean Chalard } else { 2418553b5ec315660ab53dd9234e64e1e39ea09ec0fJean Chalard dv.setVisibility(GONE); 2426f7218627eda110a8454053f8ecb7b80edfdc8cesatok } 2437e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka } else { 2447e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka dv.setVisibility(GONE); 2457e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka } 246ddb61ea461b920d87be4ad78c8a36eec1013b965Tadashi G. Takaoka if (i > 0) 247ddb61ea461b920d87be4ad78c8a36eec1013b965Tadashi G. Takaoka addView(mDividers.get(i - 1)); 248e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka addView(v); 249923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 250e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka 2517a722cbfc8bbb8a7b260895266a0fd3a9baf1994Amith Yamasani scrollTo(0, getScrollY()); 252923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project requestLayout(); 253923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 254923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 25555b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka public void onAutoCorrectionInverted(CharSequence autoCorrectedWord) { 25655b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka // Displaying auto corrected word as inverted is enabled only when highlighting candidate 25755b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka // with color is disabled. 25855b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka if (mConfigCandidateHighlightFontColorEnabled) 25955b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka return; 26055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka final TextView tv = (TextView)mWords.get(1).findViewById(R.id.candidate_word); 26155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka final Spannable word = new SpannableString(autoCorrectedWord); 26255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka final int wordLength = word.length(); 2638553b5ec315660ab53dd9234e64e1e39ea09ec0fJean Chalard word.setSpan(mInvertedBackgroundColorSpan, 0, wordLength, 2648553b5ec315660ab53dd9234e64e1e39ea09ec0fJean Chalard Spanned.SPAN_INCLUSIVE_EXCLUSIVE); 2658553b5ec315660ab53dd9234e64e1e39ea09ec0fJean Chalard word.setSpan(mInvertedForegroundColorSpan, 0, wordLength, 2668553b5ec315660ab53dd9234e64e1e39ea09ec0fJean Chalard Spanned.SPAN_INCLUSIVE_EXCLUSIVE); 26755b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka tv.setText(word); 26855b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka mShowingAutoCorrectionInverted = true; 26955b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka } 27055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 2717e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka public boolean isConfigCandidateHighlightFontColorEnabled() { 2727e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka return mConfigCandidateHighlightFontColorEnabled; 2737e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka } 2747e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka 275b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani public boolean isShowingAddToDictionaryHint() { 276b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani return mShowingAddToDictionary; 277b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani } 278b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani 27966a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani public void showAddToDictionaryHint(CharSequence word) { 2807e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka SuggestedWords.Builder builder = new SuggestedWords.Builder() 2817e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka .addWord(word) 2827e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka .addWord(getContext().getText(R.string.hint_add_to_dictionary)); 2837e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka setSuggestions(builder.build()); 28466a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani mShowingAddToDictionary = true; 285e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka // Disable R.string.hint_add_to_dictionary button 286f20eb55d4f8063f89c6c0abb3af3029fe23cb845Tadashi G. Takaoka TextView tv = (TextView)mWords.get(1).findViewById(R.id.candidate_word); 287e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka tv.setClickable(false); 28866a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani } 28966a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani 2906558253160e2039c87f424bd814f402ecd31de3bKen Wakasa public boolean dismissAddToDictionaryHint() { 2916558253160e2039c87f424bd814f402ecd31de3bKen Wakasa if (!mShowingAddToDictionary) return false; 2926558253160e2039c87f424bd814f402ecd31de3bKen Wakasa clear(); 2936558253160e2039c87f424bd814f402ecd31de3bKen Wakasa return true; 2946558253160e2039c87f424bd814f402ecd31de3bKen Wakasa } 2956558253160e2039c87f424bd814f402ecd31de3bKen Wakasa 2967e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka public SuggestedWords getSuggestions() { 297979f8690967ff5409fe18f5085858ccdb8e0ccf1satok return mSuggestions; 298979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 299979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 300923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public void clear() { 30166a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani mShowingAddToDictionary = false; 30255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka mShowingAutoCorrectionInverted = false; 303e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka removeAllViews(); 304923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 305923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 3066ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani private void hidePreview() { 307179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaoka mPreviewPopup.dismiss(); 3086ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani } 309e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka 310e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka private void showPreview(int index, CharSequence word) { 311e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka if (TextUtils.isEmpty(word)) 312e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka return; 313e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka 314e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka final TextView previewText = mPreviewText; 315e9311bc893c71f2a016d67ddb6b6234661e8a4f6Tadashi G. Takaoka previewText.setTextColor(mColorNormal); 316e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka previewText.setText(word); 317e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka previewText.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), 318e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); 319f20eb55d4f8063f89c6c0abb3af3029fe23cb845Tadashi G. Takaoka View v = mWords.get(index); 320e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka final int[] offsetInWindow = new int[2]; 321e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka v.getLocationInWindow(offsetInWindow); 322e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka final int posX = offsetInWindow[0]; 323e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka final int posY = offsetInWindow[1] - previewText.getMeasuredHeight(); 324e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka final PopupWindow previewPopup = mPreviewPopup; 325e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka if (previewPopup.isShowing()) { 326e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka previewPopup.update(posX, posY, previewPopup.getWidth(), previewPopup.getHeight()); 327e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka } else { 328e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka previewPopup.showAtLocation(this, Gravity.NO_GRAVITY, posX, posY); 329923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 330e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka previewText.setVisibility(VISIBLE); 33155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka mHandler.postHidePreview(); 332923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 333fcba53ef7c874a4685c12c01404c91b779cae1e8Tadashi G. Takaoka 334e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka private void addToDictionary(CharSequence word) { 335c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka if (mListener.addWordToDictionary(word.toString())) { 336e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka showPreview(0, getContext().getString(R.string.added_word, word)); 337e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka } 338e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka } 339e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka 340e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka @Override 341e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka public boolean onLongClick(View view) { 342e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka int index = (Integer) view.getTag(); 3437e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka CharSequence word = mSuggestions.getWord(index); 344e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka if (word.length() < 2) 345e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka return false; 346e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka addToDictionary(word); 347e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka return true; 348e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka } 349e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka 350e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka @Override 351e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka public void onClick(View view) { 352e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka int index = (Integer) view.getTag(); 3537e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka CharSequence word = mSuggestions.getWord(index); 354e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka if (mShowingAddToDictionary && index == 0) { 355e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka addToDictionary(word); 356e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka } else { 357c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka mListener.pickSuggestionManually(index, word); 358923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 359923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 36082411d47ba7e8133ed2390c6920945e139a738cesatok 3616ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani @Override 3626ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani public void onDetachedFromWindow() { 3636ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani super.onDetachedFromWindow(); 36455b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka mHandler.cancelAllMessages(); 3656ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani hidePreview(); 3666ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani } 367923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project} 368