SuggestionStripView.java revision c04bbc1ae9be81d25a356407c27a8e7fa22028bf
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; 2108a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaokaimport android.content.res.TypedArray; 226f7218627eda110a8454053f8ecb7b80edfdc8cesatokimport android.graphics.Color; 23923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.graphics.Typeface; 24e583371b13ebd9aa336d0883e8c174ae4918c758Tadashi G. Takaokaimport android.graphics.drawable.Drawable; 25e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaokaimport android.os.Message; 26522d5c16d20657e7d26009fe9c067404e16a6c2aTadashi G. Takaokaimport android.text.Spannable; 27522d5c16d20657e7d26009fe9c067404e16a6c2aTadashi G. Takaokaimport android.text.SpannableString; 28e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaokaimport android.text.Spanned; 29b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaokaimport android.text.TextPaint; 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; 3474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi 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; 41ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaokaimport android.view.View.OnLongClickListener; 42e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaokaimport android.view.ViewGroup; 43e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaokaimport android.widget.LinearLayout; 44923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.widget.PopupWindow; 45923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.widget.TextView; 46923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 47a7eed902f1b0d6871d416412b3c6f91163fa2578Tadashi G. Takaokaimport com.android.inputmethod.compat.FrameLayoutCompatUtils; 48f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaokaimport com.android.inputmethod.compat.LinearLayoutCompatUtils; 49ddb61ea461b920d87be4ad78c8a36eec1013b965Tadashi G. Takaokaimport com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; 50ddb61ea461b920d87be4ad78c8a36eec1013b965Tadashi G. Takaoka 51179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaokaimport java.util.ArrayList; 526f7218627eda110a8454053f8ecb7b80edfdc8cesatokimport java.util.List; 53179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaoka 54ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaokapublic class CandidateView extends LinearLayout implements OnClickListener, OnLongClickListener { 55c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka public interface Listener { 56c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka public boolean addWordToDictionary(String word); 57c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka public void pickSuggestionManually(int index, CharSequence word); 58c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka } 59c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka 6086e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka // The maximum number of suggestions available. See {@link Suggest#mPrefMaxSuggestions}. 6186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka private static final int MAX_SUGGESTIONS = 18; 6274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka private static final int WRAP_CONTENT = ViewGroup.LayoutParams.WRAP_CONTENT; 633118277dd47492089761c0ed1097abaeb376395cTadashi G. Takaoka private static final int MATCH_PARENT = ViewGroup.LayoutParams.MATCH_PARENT; 64923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 658553b5ec315660ab53dd9234e64e1e39ea09ec0fJean Chalard private static final boolean DBG = LatinImeLogger.sDBG; 666f7218627eda110a8454053f8ecb7b80edfdc8cesatok 6774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka private final ViewGroup mCandidatesStrip; 6886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka private ViewGroup mCandidatesPane; 6986e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka private ViewGroup mCandidatesPaneContainer; 7086e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka private View mKeyboardView; 7174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 721e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka private final ArrayList<TextView> mWords = new ArrayList<TextView>(); 732442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka private final ArrayList<TextView> mInfos = new ArrayList<TextView>(); 74ddb61ea461b920d87be4ad78c8a36eec1013b965Tadashi G. Takaoka private final ArrayList<View> mDividers = new ArrayList<View>(); 7574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 7682411d47ba7e8133ed2390c6920945e139a738cesatok private final PopupWindow mPreviewPopup; 7782411d47ba7e8133ed2390c6920945e139a738cesatok private final TextView mPreviewText; 7866a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani 79c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka private Listener mListener; 807e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka private SuggestedWords mSuggestions = SuggestedWords.EMPTY; 8155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka private boolean mShowingAutoCorrectionInverted; 826a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani 83d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka private final SuggestionsStripParams mStripParams; 84d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka private final SuggestionsPaneParams mPaneParams; 85ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka private static final float MIN_TEXT_XSCALE = 0.70f; 86b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka 874f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa private final UiHandler mHandler = new UiHandler(this); 8855b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 894f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa private static class UiHandler extends StaticInnerHandlerWrapper<CandidateView> { 9055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka private static final int MSG_HIDE_PREVIEW = 0; 9155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka private static final int MSG_UPDATE_SUGGESTION = 1; 9255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 93c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka private static final long DELAY_HIDE_PREVIEW = 1300; 9455b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka private static final long DELAY_UPDATE_SUGGESTION = 300; 9555b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 964f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa public UiHandler(CandidateView outerInstance) { 974f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa super(outerInstance); 984f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa } 994f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa 100e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka @Override 101e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka public void dispatchMessage(Message msg) { 1024f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa final CandidateView candidateView = getOuterInstance(); 103e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka switch (msg.what) { 104e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka case MSG_HIDE_PREVIEW: 1054f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa candidateView.hidePreview(); 106e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka break; 10755b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka case MSG_UPDATE_SUGGESTION: 1084f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa candidateView.updateSuggestions(); 10955b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka break; 110e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka } 111e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka } 11255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 11355b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka public void postHidePreview() { 11455b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka cancelHidePreview(); 11555b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka sendMessageDelayed(obtainMessage(MSG_HIDE_PREVIEW), DELAY_HIDE_PREVIEW); 11655b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka } 11755b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 11855b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka public void cancelHidePreview() { 11955b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka removeMessages(MSG_HIDE_PREVIEW); 12055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka } 12155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 1229fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka public void postUpdateSuggestions() { 12355b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka cancelUpdateSuggestions(); 1249fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka sendMessageDelayed(obtainMessage(MSG_UPDATE_SUGGESTION), 12555b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka DELAY_UPDATE_SUGGESTION); 12655b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka } 12755b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 12855b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka public void cancelUpdateSuggestions() { 12955b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka removeMessages(MSG_UPDATE_SUGGESTION); 13055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka } 13155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 13255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka public void cancelAllMessages() { 13355b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka cancelHidePreview(); 13455b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka cancelUpdateSuggestions(); 13555b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka } 136e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka } 137179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaoka 138d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka private static class CandidateViewParams { 13974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka public final int mPadding; 14074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka public final int mDividerWidth; 14174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka public final int mDividerHeight; 14216713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka public final int mCandidateStripHeight; 14316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka 14416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka protected final List<TextView> mWords; 14516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka protected final List<View> mDividers; 14616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka protected final List<TextView> mInfos; 147d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka 14816713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka protected CandidateViewParams(List<TextView> words, List<View> dividers, 149ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka List<TextView> infos) { 15016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka mWords = words; 15116713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka mDividers = dividers; 15216713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka mInfos = infos; 15316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka 15416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka final TextView word = words.get(0); 15516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka final View divider = dividers.get(0); 156d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka mPadding = word.getCompoundPaddingLeft() + word.getCompoundPaddingRight(); 157d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka divider.measure(WRAP_CONTENT, MATCH_PARENT); 158d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka mDividerWidth = divider.getMeasuredWidth(); 159d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka mDividerHeight = divider.getMeasuredHeight(); 16016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka 16116713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka final Resources res = word.getResources(); 16216713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka mCandidateStripHeight = res.getDimensionPixelOffset(R.dimen.candidate_strip_height); 163d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka } 164d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka } 165d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka 166d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka private static class SuggestionsPaneParams extends CandidateViewParams { 16716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka public SuggestionsPaneParams(List<TextView> words, List<View> dividers, 168ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka List<TextView> infos) { 169ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka super(words, dividers, infos); 17016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka } 17116713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka 17216713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka public int layout(SuggestedWords suggestions, ViewGroup paneView, int from, int textColor, 17316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka int paneWidth) { 17416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka final int count = Math.min(mWords.size(), suggestions.size()); 17516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka View centeringFrom = null, lastView = null; 17616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka int x = 0, y = 0; 17716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka for (int index = from; index < count; index++) { 17816713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka final int pos = index; 17916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka final TextView word = mWords.get(pos); 18016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka final View divider = mDividers.get(pos); 18116713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka final TextPaint paint = word.getPaint(); 18216713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka word.setTextColor(textColor); 18316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka final CharSequence styled = suggestions.getWord(pos); 18416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka 18516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka final TextView info; 18616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka if (DBG) { 18716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka final CharSequence debugInfo = getDebugInfo(suggestions, index); 18816713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka if (debugInfo != null) { 18916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka info = mInfos.get(index); 19016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka info.setText(debugInfo); 19116713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka } else { 19216713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka info = null; 19316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka } 19416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka } else { 19516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka info = null; 19616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka } 19716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka 19816713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka final CharSequence text; 19916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka final float scaleX; 20016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka paint.setTextScaleX(1.0f); 20116713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka final int textWidth = getTextWidth(styled, paint); 20216713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka int available = paneWidth - x - mPadding; 20316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka if (textWidth >= available) { 20416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka // Needs new row, centering previous row. 20516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka centeringCandidates(paneView, centeringFrom, lastView, x, paneWidth); 20616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka x = 0; 20716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka y += mCandidateStripHeight; 20816713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka } 20916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka if (x != 0) { 21016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka // Add divider if this isn't the left most suggestion in current row. 21116713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka paneView.addView(divider); 21216713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka FrameLayoutCompatUtils.placeViewAt(divider, x, y 21316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka + (mCandidateStripHeight - mDividerHeight) / 2, mDividerWidth, 21416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka mDividerHeight); 21516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka x += mDividerWidth; 21616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka } 21716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka available = paneWidth - x - mPadding; 21816713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka text = getEllipsizedText(styled, available, paint); 21916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka scaleX = paint.getTextScaleX(); 22016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka word.setText(text); 22116713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka word.setTextScaleX(scaleX); 22216713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka paneView.addView(word); 22316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka lastView = word; 22416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka if (x == 0) 22516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka centeringFrom = word; 22616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka word.measure(WRAP_CONTENT, 22716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka MeasureSpec.makeMeasureSpec(mCandidateStripHeight, MeasureSpec.EXACTLY)); 22816713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka final int width = word.getMeasuredWidth(); 22916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka final int height = word.getMeasuredHeight(); 23016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka FrameLayoutCompatUtils.placeViewAt(word, x, y + (mCandidateStripHeight - height) 23116713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka / 2, width, height); 23216713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka x += width; 23316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka if (info != null) { 23416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka paneView.addView(info); 23516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka lastView = info; 23616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka info.measure(WRAP_CONTENT, WRAP_CONTENT); 23716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka final int infoWidth = info.getMeasuredWidth(); 23816713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka FrameLayoutCompatUtils.placeViewAt(info, x - infoWidth, y, infoWidth, 23916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka info.getMeasuredHeight()); 24016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka } 24116713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka } 24216713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka if (x != 0) { 24316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka // Centering last candidates row. 24416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka centeringCandidates(paneView, centeringFrom, lastView, x, paneWidth); 24516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka } 24616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka 24716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka return count - from; 248d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka } 249d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka } 250d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka 251d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka private static class SuggestionsStripParams extends CandidateViewParams { 252d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka private static final int DEFAULT_CANDIDATE_COUNT_IN_STRIP = 3; 25360a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka private static final int DEFAULT_CENTER_CANDIDATE_PERCENTILE = 40; 254d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka private static final int PUNCTUATIONS_IN_STRIP = 6; 255d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka 256d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka private final int mColorTypedWord; 257d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka private final int mColorAutoCorrect; 258d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka private final int mColorSuggestedCandidate; 259d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka private final int mCandidateCountInStrip; 26060a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka private final float mCenterCandidateWeight; 26160a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka private final int mCenterCandidateIndex; 262ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka private final Drawable mMoreCandidateHint; 263d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka 264d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka private static final CharacterStyle BOLD_SPAN = new StyleSpan(Typeface.BOLD); 265d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka private static final CharacterStyle UNDERLINE_SPAN = new UnderlineSpan(); 266d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka private final CharacterStyle mInvertedForegroundColorSpan; 267d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka private final CharacterStyle mInvertedBackgroundColorSpan; 268d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka private static final int AUTO_CORRECT_BOLD = 0x01; 269d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka private static final int AUTO_CORRECT_UNDERLINE = 0x02; 270d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka private static final int AUTO_CORRECT_INVERT = 0x04; 271d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka private static final int VALID_TYPED_WORD_BOLD = 0x08; 272d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka 273d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka private final int mSuggestionStripOption; 27474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 275d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka private final ArrayList<CharSequence> mTexts = new ArrayList<CharSequence>(); 27674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 277ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka public boolean mMoreSuggestionsAvailable; 278ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka 279c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka public final TextView mWordToSaveView; 280c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka private final TextView mHintToSaveView; 281c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka private final CharSequence mHintToSaveText; 282c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka 283d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka public SuggestionsStripParams(Context context, AttributeSet attrs, int defStyle, 284ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka List<TextView> words, List<View> dividers, List<TextView> infos) { 285ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka super(words, dividers, infos); 286d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka final TypedArray a = context.obtainStyledAttributes( 287d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka attrs, R.styleable.CandidateView, defStyle, R.style.CandidateViewStyle); 288d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka mSuggestionStripOption = a.getInt(R.styleable.CandidateView_suggestionStripOption, 0); 289d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka mColorTypedWord = a.getColor(R.styleable.CandidateView_colorTypedWord, 0); 290d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka mColorAutoCorrect = a.getColor(R.styleable.CandidateView_colorAutoCorrect, 0); 291d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka mColorSuggestedCandidate = a.getColor(R.styleable.CandidateView_colorSuggested, 0); 292d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka mCandidateCountInStrip = a.getInt( 293d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka R.styleable.CandidateView_candidateCountInStrip, 294d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka DEFAULT_CANDIDATE_COUNT_IN_STRIP); 29560a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka mCenterCandidateWeight = a.getInt( 29660a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka R.styleable.CandidateView_centerCandidatePercentile, 29760a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka DEFAULT_CENTER_CANDIDATE_PERCENTILE) / 100.0f; 298d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka a.recycle(); 299d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka 30060a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka mCenterCandidateIndex = mCandidateCountInStrip / 2; 301ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka final Resources res = context.getResources(); 302ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka mMoreCandidateHint = res.getDrawable(R.drawable.more_suggestions_hint); 30360a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka 304d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka mInvertedForegroundColorSpan = new ForegroundColorSpan(mColorTypedWord ^ 0x00ffffff); 305d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka mInvertedBackgroundColorSpan = new BackgroundColorSpan(mColorTypedWord); 306d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka 307c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka final LayoutInflater inflater = LayoutInflater.from(context); 308c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka mWordToSaveView = (TextView)inflater.inflate(R.layout.candidate_word, null); 309c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka mHintToSaveView = (TextView)inflater.inflate(R.layout.candidate_word, null); 310c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka mHintToSaveText = context.getText(R.string.hint_add_to_dictionary); 31174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka } 31274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 31316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka public int getTextColor() { 31416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka return mColorTypedWord; 315d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka } 316d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka 317d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka private CharSequence getStyledCandidateWord(SuggestedWords suggestions, int pos) { 318d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka final CharSequence word = suggestions.getWord(pos); 319d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka final boolean isAutoCorrect = pos == 1 && willAutoCorrect(suggestions); 320d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka final boolean isTypedWordValid = pos == 0 && suggestions.mTypedWordValid; 321d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka if (!isAutoCorrect && !isTypedWordValid) 322d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka return word; 323d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka 324d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka final int len = word.length(); 325d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka final Spannable spannedWord = new SpannableString(word); 326d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka final int option = mSuggestionStripOption; 327d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka if ((isAutoCorrect && (option & AUTO_CORRECT_BOLD) != 0) 328d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka || (isTypedWordValid && (option & VALID_TYPED_WORD_BOLD) != 0)) { 329d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka spannedWord.setSpan(BOLD_SPAN, 0, len, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); 330d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka } 331d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka if (isAutoCorrect && (option & AUTO_CORRECT_UNDERLINE) != 0) { 332d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka spannedWord.setSpan(UNDERLINE_SPAN, 0, len, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); 333d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka } 334d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka return spannedWord; 335d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka } 336d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka 33760a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka private static boolean willAutoCorrect(SuggestedWords suggestions) { 33860a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka return !suggestions.mTypedWordValid && suggestions.mHasMinimalSuggestion; 33960a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka } 34060a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka 34160a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka private int getWordPosition(int index, SuggestedWords suggestions) { 34260a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka // TODO: This works for 3 suggestions. Revisit this algorithm when there are 5 or more 34360a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka // suggestions. 34460a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka final int centerPos = willAutoCorrect(suggestions) ? 1 : 0; 34560a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka if (index == mCenterCandidateIndex) { 34660a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka return centerPos; 34760a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka } else if (index == centerPos) { 34860a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka return mCenterCandidateIndex; 34960a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka } else { 350d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka return index; 351d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka } 352d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka } 353d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka 35460a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka private int getCandidateTextColor(int index, SuggestedWords suggestions, int pos) { 355d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka // TODO: Need to revisit this logic with bigram suggestions 356d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka final boolean isSuggestedCandidate = (pos != 0); 357d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka 358d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka final int color; 35960a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka if (index == mCenterCandidateIndex && willAutoCorrect(suggestions)) { 360d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka color = mColorAutoCorrect; 361d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka } else if (isSuggestedCandidate) { 362d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka color = mColorSuggestedCandidate; 363d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka } else { 364d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka color = mColorTypedWord; 365d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka } 36660a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka 36760a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka final SuggestedWordInfo info = (pos < suggestions.size()) 36860a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka ? suggestions.getInfo(pos) : null; 369d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka if (info != null && info.isPreviousSuggestedWord()) { 370d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka return applyAlpha(color, 0.5f); 371d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka } else { 372d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka return color; 373d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka } 374d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka } 375d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka 376d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka private static int applyAlpha(final int color, final float alpha) { 377d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka final int newAlpha = (int)(Color.alpha(color) * alpha); 378d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka return Color.argb(newAlpha, Color.red(color), Color.green(color), Color.blue(color)); 379d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka } 380d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka 381d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka public CharSequence getInvertedText(CharSequence text) { 382d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka if ((mSuggestionStripOption & AUTO_CORRECT_INVERT) == 0) 383d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka return null; 384d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka final int len = text.length(); 385d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka final Spannable word = new SpannableString(text); 386d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka word.setSpan(mInvertedBackgroundColorSpan, 0, len, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); 387d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka word.setSpan(mInvertedForegroundColorSpan, 0, len, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); 388d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka return word; 389d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka } 390d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka 39116713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka public int layout(SuggestedWords suggestions, ViewGroup stripView, ViewGroup paneView, 39216713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka int stripWidth) { 39360a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka if (suggestions.isPunctuationSuggestions()) { 39460a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka return layoutPunctuationSuggestions(suggestions, stripView); 39560a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka } 39660a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka 39760a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka final int countInStrip = mCandidateCountInStrip; 39860a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka setupTexts(suggestions, countInStrip); 399bbf25cf25169f640a361370cde5521ffc7789a1bKen Wakasa mMoreSuggestionsAvailable = (suggestions.size() > countInStrip); 40060a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka int x = 0; 40160a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka for (int index = 0; index < countInStrip; index++) { 40260a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka final int pos = getWordPosition(index, suggestions); 40360a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka 40460a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka if (index != 0) { 40560a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka final View divider = mDividers.get(pos); 40660a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka // Add divider if this isn't the left most suggestion in candidate strip. 40760a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka stripView.addView(divider); 40860a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka } 40960a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka 41016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka final CharSequence styled = mTexts.get(pos); 41160a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka final TextView word = mWords.get(pos); 412bbf25cf25169f640a361370cde5521ffc7789a1bKen Wakasa if (index == mCenterCandidateIndex && mMoreSuggestionsAvailable) { 413ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka // TODO: This "more suggestions hint" should have nicely designed icon. 414ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka word.setCompoundDrawablesWithIntrinsicBounds( 415ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka null, null, null, mMoreCandidateHint); 416580e1d7ac0cb90a464a3b3aed88047f85a4ab41fTadashi G. Takaoka // HACK: To align with other TextView that has no compound drawables. 417580e1d7ac0cb90a464a3b3aed88047f85a4ab41fTadashi G. Takaoka word.setCompoundDrawablePadding(-mMoreCandidateHint.getIntrinsicHeight()); 418ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka } else { 419580e1d7ac0cb90a464a3b3aed88047f85a4ab41fTadashi G. Takaoka word.setCompoundDrawablesWithIntrinsicBounds(null, null, null, null); 420ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka } 421ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka 42260a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka // Disable this candidate if the suggestion is null or empty. 42360a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka word.setEnabled(!TextUtils.isEmpty(styled)); 42460a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka word.setTextColor(getCandidateTextColor(index, suggestions, pos)); 425ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka final int width = getCandidateWidth(index, stripWidth); 42660a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka final CharSequence text = getEllipsizedText(styled, width, word.getPaint()); 42760a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka final float scaleX = word.getTextScaleX(); 42860a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka word.setText(text); // TextView.setText() resets text scale x to 1.0. 42960a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka word.setTextScaleX(scaleX); 43060a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka stripView.addView(word); 431580e1d7ac0cb90a464a3b3aed88047f85a4ab41fTadashi G. Takaoka setLayoutWeight(word, getCandidateWeight(index), MATCH_PARENT); 43216713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka 43316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka if (DBG) { 43460a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka final CharSequence debugInfo = getDebugInfo(suggestions, pos); 43516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka if (debugInfo != null) { 43660a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka final TextView info = mInfos.get(pos); 43716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka info.setText(debugInfo); 43816713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka paneView.addView(info); 43916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka info.measure(WRAP_CONTENT, WRAP_CONTENT); 44060a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka final int infoWidth = info.getMeasuredWidth(); 44116713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka final int y = info.getMeasuredHeight(); 44260a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka FrameLayoutCompatUtils.placeViewAt(info, x, 0, infoWidth, y); 44360a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka x += infoWidth * 2; 44416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka } 44560a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka } 44616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka } 44716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka 44860a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka return countInStrip; 44916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka } 45016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka 45160a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka private int getCandidateWidth(int index, int maxWidth) { 45260a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka final int paddings = mPadding * mCandidateCountInStrip; 45360a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka final int dividers = mDividerWidth * (mCandidateCountInStrip - 1); 45460a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka final int availableWidth = maxWidth - paddings - dividers; 45560a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka return (int)(availableWidth * getCandidateWeight(index)); 45660a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka } 45774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 45860a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka private float getCandidateWeight(int index) { 45960a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka if (index == mCenterCandidateIndex) { 46060a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka return mCenterCandidateWeight; 46160a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka } else { 46260a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka // TODO: Revisit this for cases of 5 or more suggestions 46360a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka return (1.0f - mCenterCandidateWeight) / (mCandidateCountInStrip - 1); 46474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka } 46574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka } 46674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 46760a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka private void setupTexts(SuggestedWords suggestions, int countInStrip) { 46874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mTexts.clear(); 46960a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka final int count = Math.min(suggestions.size(), countInStrip); 47060a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka for (int pos = 0; pos < count; pos++) { 471d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka final CharSequence styled = getStyledCandidateWord(suggestions, pos); 47274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mTexts.add(styled); 47374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka } 47460a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka for (int pos = count; pos < countInStrip; pos++) { 47560a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka // Make this inactive for touches in layout(). 47660a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka mTexts.add(null); 47760a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka } 47874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka } 47974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 48060a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka private int layoutPunctuationSuggestions(SuggestedWords suggestions, ViewGroup stripView) { 48160a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka final int countInStrip = Math.min(suggestions.size(), PUNCTUATIONS_IN_STRIP); 48260a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka for (int index = 0; index < countInStrip; index++) { 48360a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka if (index != 0) { 48460a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka // Add divider if this isn't the left most suggestion in candidate strip. 48560a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka stripView.addView(mDividers.get(index)); 48660a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka } 48760a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka 48860a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka final TextView word = mWords.get(index); 48960a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka word.setEnabled(true); 49060a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka word.setTextColor(mColorTypedWord); 49160a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka final CharSequence text = suggestions.getWord(index); 49260a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka word.setText(text); 49360a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka word.setTextScaleX(1.0f); 494ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka word.setCompoundDrawables(null, null, null, null); 49560a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka stripView.addView(word); 49660a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka setLayoutWeight(word, 1.0f, mCandidateStripHeight); 49760a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka } 498ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka mMoreSuggestionsAvailable = false; 49960a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka return countInStrip; 50074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka } 501c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka 502c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka public void layoutAddToDictionaryHint(CharSequence word, ViewGroup stripView, 503c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka int stripWidth) { 504c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka final int width = stripWidth - mDividerWidth - mPadding * 2; 505c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka 506c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka final TextView wordView = mWordToSaveView; 507c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka wordView.setTextColor(mColorTypedWord); 508c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka final int wordWidth = (int)(width * mCenterCandidateWeight); 509c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka final CharSequence text = getEllipsizedText(word, wordWidth, wordView.getPaint()); 510c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka final float wordScaleX = wordView.getTextScaleX(); 511c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka wordView.setTag(word); 512c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka wordView.setText(text); 513c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka wordView.setTextScaleX(wordScaleX); 514c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka stripView.addView(wordView); 515c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka setLayoutWeight(wordView, mCenterCandidateWeight, MATCH_PARENT); 516c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka 517c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka stripView.addView(mDividers.get(0)); 518c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka 519c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka final TextView hintView = mHintToSaveView; 520c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka hintView.setTextColor(mColorAutoCorrect); 521c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka final int hintWidth = width - wordWidth; 522c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka final float hintScaleX = getTextScaleX(mHintToSaveText, hintWidth, hintView.getPaint()); 523c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka hintView.setText(mHintToSaveText); 524c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka hintView.setTextScaleX(hintScaleX); 525c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka stripView.addView(hintView); 526c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka setLayoutWeight(hintView, 1.0f - mCenterCandidateWeight, MATCH_PARENT); 527c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka } 52874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka } 52974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 530923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 531923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Construct a CandidateView for showing suggested words for completion. 532923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * @param context 533923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * @param attrs 534923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 535923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public CandidateView(Context context, AttributeSet attrs) { 53608a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka this(context, attrs, R.attr.candidateViewStyle); 53708a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka } 53808a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka 53908a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka public CandidateView(Context context, AttributeSet attrs, int defStyle) { 540f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka // Note: Up to version 10 (Gingerbread) of the API, LinearLayout doesn't have 3-argument 541f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka // constructor. 542f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka // TODO: Call 3-argument constructor, super(context, attrs, defStyle), when we abandon 543f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka // backward compatibility with the version 10 or earlier of the API. 544f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka super(context, attrs); 545f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka if (defStyle != R.attr.candidateViewStyle) { 546f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka throw new IllegalArgumentException( 547c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka "can't accept defStyle other than R.attr.candidateViewStyle: defStyle=" 548f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka + defStyle); 549f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka } 550f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka setBackgroundDrawable(LinearLayoutCompatUtils.getBackgroundDrawable( 551f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka context, attrs, defStyle, R.style.CandidateViewStyle)); 552923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 55316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka final LayoutInflater inflater = LayoutInflater.from(context); 55486e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka inflater.inflate(R.layout.candidates_strip, this); 55586e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka 55686e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka mPreviewPopup = new PopupWindow(context); 557e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka mPreviewText = (TextView) inflater.inflate(R.layout.candidate_preview, null); 558580e1d7ac0cb90a464a3b3aed88047f85a4ab41fTadashi G. Takaoka mPreviewPopup.setWindowLayoutMode(WRAP_CONTENT, WRAP_CONTENT); 559923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project mPreviewPopup.setContentView(mPreviewText); 560923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project mPreviewPopup.setBackgroundDrawable(null); 561923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 56274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mCandidatesStrip = (ViewGroup)findViewById(R.id.candidates_strip); 56360a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka for (int pos = 0; pos < MAX_SUGGESTIONS; pos++) { 56474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka final TextView word = (TextView)inflater.inflate(R.layout.candidate_word, null); 56560a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka word.setTag(pos); 5662442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka word.setOnClickListener(this); 567ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka word.setOnLongClickListener(this); 5682442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka mWords.add(word); 569a1aab83a24e74cb0fad4b1c1e59b18d23ecbdad3Tadashi G. Takaoka final View divider = inflater.inflate(R.layout.candidate_divider, null); 57060a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka divider.setTag(pos); 571a1aab83a24e74cb0fad4b1c1e59b18d23ecbdad3Tadashi G. Takaoka divider.setOnClickListener(this); 572a1aab83a24e74cb0fad4b1c1e59b18d23ecbdad3Tadashi G. Takaoka mDividers.add(divider); 57374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mInfos.add((TextView)inflater.inflate(R.layout.candidate_info, null)); 574c9716b28ce438e06b5cacc07fc002944bcbe24a0Tadashi G. Takaoka } 575179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaoka 576ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka mStripParams = new SuggestionsStripParams(context, attrs, defStyle, mWords, mDividers, 577ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka mInfos); 578ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka mPaneParams = new SuggestionsPaneParams(mWords, mDividers, mInfos); 579c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka mStripParams.mWordToSaveView.setOnClickListener(this); 580923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 581c9716b28ce438e06b5cacc07fc002944bcbe24a0Tadashi G. Takaoka 582923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 583c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka * A connection back to the input method. 584923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * @param listener 585923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 58686e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka public void setListener(Listener listener, View inputView) { 587c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka mListener = listener; 58886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka mKeyboardView = inputView.findViewById(R.id.keyboard_view); 589a7eed902f1b0d6871d416412b3c6f91163fa2578Tadashi G. Takaoka mCandidatesPane = FrameLayoutCompatUtils.getPlacer( 590a7eed902f1b0d6871d416412b3c6f91163fa2578Tadashi G. Takaoka (ViewGroup)inputView.findViewById(R.id.candidates_pane)); 59186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka mCandidatesPane.setOnClickListener(this); 59286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka mCandidatesPaneContainer = (ViewGroup)inputView.findViewById( 59386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka R.id.candidates_pane_container); 594923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 595923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 5967e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka public void setSuggestions(SuggestedWords suggestions) { 5979fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka if (suggestions == null) 598a15e45ef45931ba46678b39c159518d8aa2d4d65Tadashi G. Takaoka return; 5999fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka mSuggestions = suggestions; 60055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka if (mShowingAutoCorrectionInverted) { 6019fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka mHandler.postUpdateSuggestions(); 60255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka } else { 6039fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka updateSuggestions(); 60455b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka } 60555b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka } 60655b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 6079fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka private void updateSuggestions() { 608e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka clear(); 60986e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka closeCandidatesPane(); 61016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka if (mSuggestions.size() == 0) 61174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka return; 61274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 61316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka final int width = getWidth(); 61416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka final int countInStrip = mStripParams.layout( 61516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka mSuggestions, mCandidatesStrip, mCandidatesPane, width); 616bea6b72106853747302fcca11957647982384220Tadashi G. Takaoka mPaneParams.layout( 61716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka mSuggestions, mCandidatesPane, countInStrip, mStripParams.getTextColor(), width); 61816713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka } 61974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 62016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka private static CharSequence getDebugInfo(SuggestedWords suggestions, int pos) { 62160a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka if (DBG && pos < suggestions.size()) { 62216713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka final SuggestedWordInfo wordInfo = suggestions.getInfo(pos); 62316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka if (wordInfo != null) { 62416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka final CharSequence debugInfo = wordInfo.getDebugString(); 62516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka if (!TextUtils.isEmpty(debugInfo)) { 62616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka return debugInfo; 627d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka } 6282442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka } 62986e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka } 63016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka return null; 63186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka } 63286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka 6333118277dd47492089761c0ed1097abaeb376395cTadashi G. Takaoka private static void setLayoutWeight(View v, float weight, int height) { 63474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka final ViewGroup.LayoutParams lp = v.getLayoutParams(); 63574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka if (lp instanceof LinearLayout.LayoutParams) { 63674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka final LinearLayout.LayoutParams llp = (LinearLayout.LayoutParams)lp; 63774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka llp.weight = weight; 63874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka llp.width = 0; 6393118277dd47492089761c0ed1097abaeb376395cTadashi G. Takaoka llp.height = height; 64074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka } 64174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka } 64274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 64316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka private static void centeringCandidates(ViewGroup parent, View from, View to, int width, 64416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka int parentWidth) { 64516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka final int fromIndex = parent.indexOfChild(from); 64616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka final int toIndex = parent.indexOfChild(to); 64716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka final int offset = (parentWidth - width) / 2; 64886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka for (int index = fromIndex; index <= toIndex; index++) { 64916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka offsetMargin(parent.getChildAt(index), offset, 0); 65086e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka } 65186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka } 65286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka 65386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka private static void offsetMargin(View v, int dx, int dy) { 654862e05a8f0aa03ddc4582d5bf68a3201f348cf1dTadashi G. Takaoka if (v == null) 655862e05a8f0aa03ddc4582d5bf68a3201f348cf1dTadashi G. Takaoka return; 6562442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka final ViewGroup.LayoutParams lp = v.getLayoutParams(); 65786e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka if (lp instanceof ViewGroup.MarginLayoutParams) { 6582442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka final ViewGroup.MarginLayoutParams mlp = (ViewGroup.MarginLayoutParams)lp; 65986e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka mlp.setMargins(mlp.leftMargin + dx, mlp.topMargin + dy, 0, 0); 66086e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka } 66186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka } 66286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka 663c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka private static float getTextScaleX(CharSequence text, int maxWidth, TextPaint paint) { 664c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka paint.setTextScaleX(1.0f); 665c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka final int width = getTextWidth(text, paint); 666c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka if (width <= maxWidth) { 667c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka return 1.0f; 668c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka } 669c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka return maxWidth / (float)width; 670c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka } 671c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka 67274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka private static CharSequence getEllipsizedText(CharSequence text, int maxWidth, 67374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka TextPaint paint) { 6745cb10f78ed5c0e17798ea5300d8291b613c5e2a9Tadashi G. Takaoka if (text == null) return null; 67574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka paint.setTextScaleX(1.0f); 67674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka final int width = getTextWidth(text, paint); 67760a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka if (width <= maxWidth) { 67860a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka return text; 67960a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka } 68060a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka final float scaleX = maxWidth / (float)width; 681b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka if (scaleX >= MIN_TEXT_XSCALE) { 68274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka paint.setTextScaleX(scaleX); 68374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka return text; 684b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka } 685b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka 68674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka // Note that TextUtils.ellipsize() use text-x-scale as 1.0 if ellipsize is needed. To get 68760a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka // squeezed and ellipsized text, passes enlarged width (maxWidth / MIN_TEXT_XSCALE). 68874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka final CharSequence ellipsized = TextUtils.ellipsize( 68974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka text, paint, maxWidth / MIN_TEXT_XSCALE, TextUtils.TruncateAt.MIDDLE); 69074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka paint.setTextScaleX(MIN_TEXT_XSCALE); 69174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka return ellipsized; 692b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka } 693b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka 69474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka private static int getTextWidth(CharSequence text, TextPaint paint) { 695b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka if (TextUtils.isEmpty(text)) return 0; 696fe9b65afa84530d17dd82c770c19de763a50cb58Tadashi G. Takaoka final Typeface savedTypeface = paint.getTypeface(); 69774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka paint.setTypeface(getTextTypeface(text)); 698b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka final int len = text.length(); 699b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka final float[] widths = new float[len]; 700b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka final int count = paint.getTextWidths(text, 0, len, widths); 701fe9b65afa84530d17dd82c770c19de763a50cb58Tadashi G. Takaoka int width = 0; 702b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka for (int i = 0; i < count; i++) { 703fe9b65afa84530d17dd82c770c19de763a50cb58Tadashi G. Takaoka width += Math.round(widths[i] + 0.5f); 704b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka } 705fe9b65afa84530d17dd82c770c19de763a50cb58Tadashi G. Takaoka paint.setTypeface(savedTypeface); 706fe9b65afa84530d17dd82c770c19de763a50cb58Tadashi G. Takaoka return width; 707b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka } 708b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka 70974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka private static Typeface getTextTypeface(CharSequence text) { 71074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka if (!(text instanceof SpannableString)) 71174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka return Typeface.DEFAULT; 71274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 71374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka final SpannableString ss = (SpannableString)text; 71474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka final StyleSpan[] styles = ss.getSpans(0, text.length(), StyleSpan.class); 71574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka if (styles.length == 0) 71674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka return Typeface.DEFAULT; 71774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 71874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka switch (styles[0].getStyle()) { 71974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka case Typeface.BOLD: return Typeface.DEFAULT_BOLD; 72074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka // TODO: BOLD_ITALIC, ITALIC case? 72174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka default: return Typeface.DEFAULT; 722b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka } 723b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka } 724b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka 72586e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka private void expandCandidatesPane() { 72686e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka mCandidatesPaneContainer.setMinimumHeight(mKeyboardView.getMeasuredHeight()); 72774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mCandidatesPaneContainer.setVisibility(VISIBLE); 72874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mKeyboardView.setVisibility(GONE); 72986e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka } 730e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka 73186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka private void closeCandidatesPane() { 73274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mCandidatesPaneContainer.setVisibility(GONE); 73374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mKeyboardView.setVisibility(VISIBLE); 734923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 735923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 736bbf25cf25169f640a361370cde5521ffc7789a1bKen Wakasa private void toggleCandidatesPane() { 737bbf25cf25169f640a361370cde5521ffc7789a1bKen Wakasa if (mCandidatesPaneContainer.getVisibility() == VISIBLE) { 738bbf25cf25169f640a361370cde5521ffc7789a1bKen Wakasa closeCandidatesPane(); 739bbf25cf25169f640a361370cde5521ffc7789a1bKen Wakasa } else { 740bbf25cf25169f640a361370cde5521ffc7789a1bKen Wakasa expandCandidatesPane(); 741bbf25cf25169f640a361370cde5521ffc7789a1bKen Wakasa } 742bbf25cf25169f640a361370cde5521ffc7789a1bKen Wakasa } 743bbf25cf25169f640a361370cde5521ffc7789a1bKen Wakasa 74455b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka public void onAutoCorrectionInverted(CharSequence autoCorrectedWord) { 745d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka final CharSequence inverted = mStripParams.getInvertedText(autoCorrectedWord); 746d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka if (inverted == null) 74755b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka return; 7481e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka final TextView tv = mWords.get(1); 749d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka tv.setText(inverted); 75055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka mShowingAutoCorrectionInverted = true; 75155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka } 75255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 753b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani public boolean isShowingAddToDictionaryHint() { 754c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka return mCandidatesStrip.getChildCount() > 0 755c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka && mCandidatesStrip.getChildAt(0) == mStripParams.mWordToSaveView; 756b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani } 757b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani 75866a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani public void showAddToDictionaryHint(CharSequence word) { 759c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka clear(); 760c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka mStripParams.layoutAddToDictionaryHint(word, mCandidatesStrip, getWidth()); 76166a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani } 76266a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani 7636558253160e2039c87f424bd814f402ecd31de3bKen Wakasa public boolean dismissAddToDictionaryHint() { 764c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka if (isShowingAddToDictionaryHint()) { 765c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka clear(); 766c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka return true; 767c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka } 768c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka return false; 7696558253160e2039c87f424bd814f402ecd31de3bKen Wakasa } 7706558253160e2039c87f424bd814f402ecd31de3bKen Wakasa 7717e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka public SuggestedWords getSuggestions() { 772979f8690967ff5409fe18f5085858ccdb8e0ccf1satok return mSuggestions; 773979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 774979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 775923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public void clear() { 77655b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka mShowingAutoCorrectionInverted = false; 77774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mCandidatesStrip.removeAllViews(); 77886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka mCandidatesPane.removeAllViews(); 77988110d1799146943c627916ffaa94bbc4dd6f2aeTadashi G. Takaoka closeCandidatesPane(); 780923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 781923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 7826ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani private void hidePreview() { 783179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaoka mPreviewPopup.dismiss(); 7846ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani } 785e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka 786c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka private void showPreview(View view, CharSequence word) { 787e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka if (TextUtils.isEmpty(word)) 788e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka return; 789e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka 790e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka final TextView previewText = mPreviewText; 791d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka previewText.setTextColor(mStripParams.mColorTypedWord); 792e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka previewText.setText(word); 793e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka previewText.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), 794e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); 795e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka final int[] offsetInWindow = new int[2]; 796c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka view.getLocationInWindow(offsetInWindow); 797e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka final int posX = offsetInWindow[0]; 798e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka final int posY = offsetInWindow[1] - previewText.getMeasuredHeight(); 799e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka final PopupWindow previewPopup = mPreviewPopup; 800e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka if (previewPopup.isShowing()) { 801e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka previewPopup.update(posX, posY, previewPopup.getWidth(), previewPopup.getHeight()); 802e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka } else { 803e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka previewPopup.showAtLocation(this, Gravity.NO_GRAVITY, posX, posY); 804923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 805e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka previewText.setVisibility(VISIBLE); 80655b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka mHandler.postHidePreview(); 807923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 808fcba53ef7c874a4685c12c01404c91b779cae1e8Tadashi G. Takaoka 809e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka private void addToDictionary(CharSequence word) { 810c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka if (mListener.addWordToDictionary(word.toString())) { 811c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka final CharSequence message = getContext().getString(R.string.added_word, word); 812c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka showPreview(mStripParams.mWordToSaveView, message); 813e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka } 814e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka } 815e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka 816e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka @Override 817ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka public boolean onLongClick(View view) { 818ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka if (mStripParams.mMoreSuggestionsAvailable) { 819bbf25cf25169f640a361370cde5521ffc7789a1bKen Wakasa toggleCandidatesPane(); 820ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka return true; 821ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka } 822ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka return false; 823ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka } 824ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka 825ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka @Override 826e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka public void onClick(View view) { 827c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka if (view == mStripParams.mWordToSaveView) { 828c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka addToDictionary((CharSequence)view.getTag()); 829717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka clear(); 830717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka return; 831717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka } 832717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka 833ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka if (view == mCandidatesPane) { 834ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka closeCandidatesPane(); 835ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka return; 836ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka } 837ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka 83886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka final Object tag = view.getTag(); 83986e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka if (!(tag instanceof Integer)) 84086e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka return; 84186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka final int index = (Integer) tag; 84237deb112c727dfed5e94d054cf5f00f5d60c8120Tadashi G. Takaoka if (index >= mSuggestions.size()) 84337deb112c727dfed5e94d054cf5f00f5d60c8120Tadashi G. Takaoka return; 84486e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka 84537deb112c727dfed5e94d054cf5f00f5d60c8120Tadashi G. Takaoka final CharSequence word = mSuggestions.getWord(index); 846717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka mListener.pickSuggestionManually(index, word); 84786e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka // Because some punctuation letters are not treated as word separator depending on locale, 84886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka // {@link #setSuggestions} might not be called and candidates pane left opened. 84986e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka closeCandidatesPane(); 850923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 85182411d47ba7e8133ed2390c6920945e139a738cesatok 8526ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani @Override 8536ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani public void onDetachedFromWindow() { 8546ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani super.onDetachedFromWindow(); 85555b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka mHandler.cancelAllMessages(); 8566ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani hidePreview(); 8576ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani } 858923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project} 859