SuggestionStripView.java revision 16713e5630b93fb5625df26745eb73271f189457
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; 41e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaokaimport android.view.ViewGroup; 42e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaokaimport android.widget.LinearLayout; 43923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.widget.PopupWindow; 44923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.widget.TextView; 45923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 46a7eed902f1b0d6871d416412b3c6f91163fa2578Tadashi G. Takaokaimport com.android.inputmethod.compat.FrameLayoutCompatUtils; 47f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaokaimport com.android.inputmethod.compat.LinearLayoutCompatUtils; 48ddb61ea461b920d87be4ad78c8a36eec1013b965Tadashi G. Takaokaimport com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; 49ddb61ea461b920d87be4ad78c8a36eec1013b965Tadashi G. Takaoka 50179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaokaimport java.util.ArrayList; 516f7218627eda110a8454053f8ecb7b80edfdc8cesatokimport java.util.List; 52179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaoka 535ab5807d9163380b56350d5043883c1ea944128cTadashi G. Takaokapublic class CandidateView extends LinearLayout implements OnClickListener { 54923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 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; 6874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka private final ViewGroup mCandidatesPaneControl; 6974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka private final TextView mExpandCandidatesPane; 7074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka private final TextView mCloseCandidatesPane; 7186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka private ViewGroup mCandidatesPane; 7286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka private ViewGroup mCandidatesPaneContainer; 7386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka private View mKeyboardView; 7474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 751e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka private final ArrayList<TextView> mWords = new ArrayList<TextView>(); 762442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka private final ArrayList<TextView> mInfos = new ArrayList<TextView>(); 77ddb61ea461b920d87be4ad78c8a36eec1013b965Tadashi G. Takaoka private final ArrayList<View> mDividers = new ArrayList<View>(); 7874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 7982411d47ba7e8133ed2390c6920945e139a738cesatok private final PopupWindow mPreviewPopup; 8082411d47ba7e8133ed2390c6920945e139a738cesatok private final TextView mPreviewText; 8166a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani 82717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka private final View mTouchToSave; 83717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka private final TextView mWordToSave; 84717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka 85c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka private Listener mListener; 867e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka private SuggestedWords mSuggestions = SuggestedWords.EMPTY; 8755b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka private boolean mShowingAutoCorrectionInverted; 88e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka private boolean mShowingAddToDictionary; 896a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani 90d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka private final SuggestionsStripParams mStripParams; 91d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka private final SuggestionsPaneParams mPaneParams; 92fe9b65afa84530d17dd82c770c19de763a50cb58Tadashi G. Takaoka private static final float MIN_TEXT_XSCALE = 0.75f; 93b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka 944f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa private final UiHandler mHandler = new UiHandler(this); 9555b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 964f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa private static class UiHandler extends StaticInnerHandlerWrapper<CandidateView> { 9755b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka private static final int MSG_HIDE_PREVIEW = 0; 9855b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka private static final int MSG_UPDATE_SUGGESTION = 1; 9955b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 10055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka private static final long DELAY_HIDE_PREVIEW = 1000; 10155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka private static final long DELAY_UPDATE_SUGGESTION = 300; 10255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 1034f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa public UiHandler(CandidateView outerInstance) { 1044f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa super(outerInstance); 1054f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa } 1064f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa 107e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka @Override 108e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka public void dispatchMessage(Message msg) { 1094f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa final CandidateView candidateView = getOuterInstance(); 110e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka switch (msg.what) { 111e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka case MSG_HIDE_PREVIEW: 1124f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa candidateView.hidePreview(); 113e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka break; 11455b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka case MSG_UPDATE_SUGGESTION: 1154f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa candidateView.updateSuggestions(); 11655b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka break; 117e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka } 118e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka } 11955b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 12055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka public void postHidePreview() { 12155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka cancelHidePreview(); 12255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka sendMessageDelayed(obtainMessage(MSG_HIDE_PREVIEW), DELAY_HIDE_PREVIEW); 12355b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka } 12455b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 12555b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka public void cancelHidePreview() { 12655b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka removeMessages(MSG_HIDE_PREVIEW); 12755b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka } 12855b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 1299fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka public void postUpdateSuggestions() { 13055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka cancelUpdateSuggestions(); 1319fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka sendMessageDelayed(obtainMessage(MSG_UPDATE_SUGGESTION), 13255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka DELAY_UPDATE_SUGGESTION); 13355b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka } 13455b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 13555b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka public void cancelUpdateSuggestions() { 13655b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka removeMessages(MSG_UPDATE_SUGGESTION); 13755b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka } 13855b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 13955b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka public void cancelAllMessages() { 14055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka cancelHidePreview(); 14155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka cancelUpdateSuggestions(); 14255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka } 143e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka } 144179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaoka 145d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka private static class CandidateViewParams { 14674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka public final int mPadding; 14774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka public final int mDividerWidth; 14874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka public final int mDividerHeight; 14974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka public final int mControlWidth; 15016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka public final int mCandidateStripHeight; 15116713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka 15216713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka protected final List<TextView> mWords; 15316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka protected final List<View> mDividers; 15416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka protected final List<TextView> mInfos; 155d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka 15616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka protected CandidateViewParams(List<TextView> words, List<View> dividers, 15716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka List<TextView> infos, View control) { 15816713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka mWords = words; 15916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka mDividers = dividers; 16016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka mInfos = infos; 16116713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka 16216713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka final TextView word = words.get(0); 16316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka final View divider = dividers.get(0); 164d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka mPadding = word.getCompoundPaddingLeft() + word.getCompoundPaddingRight(); 165d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka divider.measure(WRAP_CONTENT, MATCH_PARENT); 166d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka mDividerWidth = divider.getMeasuredWidth(); 167d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka mDividerHeight = divider.getMeasuredHeight(); 168d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka mControlWidth = control.getMeasuredWidth(); 16916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka 17016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka final Resources res = word.getResources(); 17116713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka mCandidateStripHeight = res.getDimensionPixelOffset(R.dimen.candidate_strip_height); 172d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka } 173d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka } 174d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka 175d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka private static class SuggestionsPaneParams extends CandidateViewParams { 17616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka public SuggestionsPaneParams(List<TextView> words, List<View> dividers, 17716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka List<TextView> infos, View control) { 17816713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka super(words, dividers, infos, control); 17916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka } 18016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka 18116713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka public int layout(SuggestedWords suggestions, ViewGroup paneView, int from, int textColor, 18216713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka int paneWidth) { 18316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka final int count = Math.min(mWords.size(), suggestions.size()); 18416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka View centeringFrom = null, lastView = null; 18516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka int x = 0, y = 0; 18616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka for (int index = from; index < count; index++) { 18716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka final int pos = index; 18816713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka final TextView word = mWords.get(pos); 18916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka final View divider = mDividers.get(pos); 19016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka final TextPaint paint = word.getPaint(); 19116713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka word.setTextColor(textColor); 19216713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka final CharSequence styled = suggestions.getWord(pos); 19316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka 19416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka final TextView info; 19516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka if (DBG) { 19616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka final CharSequence debugInfo = getDebugInfo(suggestions, index); 19716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka if (debugInfo != null) { 19816713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka info = mInfos.get(index); 19916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka info.setText(debugInfo); 20016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka } else { 20116713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka info = null; 20216713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka } 20316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka } else { 20416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka info = null; 20516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka } 20616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka 20716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka final CharSequence text; 20816713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka final float scaleX; 20916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka paint.setTextScaleX(1.0f); 21016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka final int textWidth = getTextWidth(styled, paint); 21116713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka int available = paneWidth - x - mPadding; 21216713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka if (textWidth >= available) { 21316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka // Needs new row, centering previous row. 21416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka centeringCandidates(paneView, centeringFrom, lastView, x, paneWidth); 21516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka x = 0; 21616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka y += mCandidateStripHeight; 21716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka } 21816713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka if (x != 0) { 21916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka // Add divider if this isn't the left most suggestion in current row. 22016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka paneView.addView(divider); 22116713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka FrameLayoutCompatUtils.placeViewAt(divider, x, y 22216713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka + (mCandidateStripHeight - mDividerHeight) / 2, mDividerWidth, 22316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka mDividerHeight); 22416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka x += mDividerWidth; 22516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka } 22616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka available = paneWidth - x - mPadding; 22716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka text = getEllipsizedText(styled, available, paint); 22816713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka scaleX = paint.getTextScaleX(); 22916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka word.setText(text); 23016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka word.setTextScaleX(scaleX); 23116713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka paneView.addView(word); 23216713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka lastView = word; 23316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka if (x == 0) 23416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka centeringFrom = word; 23516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka word.measure(WRAP_CONTENT, 23616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka MeasureSpec.makeMeasureSpec(mCandidateStripHeight, MeasureSpec.EXACTLY)); 23716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka final int width = word.getMeasuredWidth(); 23816713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka final int height = word.getMeasuredHeight(); 23916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka FrameLayoutCompatUtils.placeViewAt(word, x, y + (mCandidateStripHeight - height) 24016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka / 2, width, height); 24116713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka x += width; 24216713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka if (info != null) { 24316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka paneView.addView(info); 24416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka lastView = info; 24516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka info.measure(WRAP_CONTENT, WRAP_CONTENT); 24616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka final int infoWidth = info.getMeasuredWidth(); 24716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka FrameLayoutCompatUtils.placeViewAt(info, x - infoWidth, y, infoWidth, 24816713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka info.getMeasuredHeight()); 24916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka } 25016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka } 25116713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka if (x != 0) { 25216713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka // Centering last candidates row. 25316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka centeringCandidates(paneView, centeringFrom, lastView, x, paneWidth); 25416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka } 25516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka 25616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka return count - from; 257d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka } 258d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka } 259d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka 260d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka private static class SuggestionsStripParams extends CandidateViewParams { 261d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka private static final int DEFAULT_CANDIDATE_COUNT_IN_STRIP = 3; 262d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka private static final int PUNCTUATIONS_IN_STRIP = 6; 263d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka 264d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka private final int mColorTypedWord; 265d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka private final int mColorAutoCorrect; 266d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka private final int mColorSuggestedCandidate; 267d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka private final int mCandidateCountInStrip; 268d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka 269d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka private static final CharacterStyle BOLD_SPAN = new StyleSpan(Typeface.BOLD); 270d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka private static final CharacterStyle UNDERLINE_SPAN = new UnderlineSpan(); 271d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka private final CharacterStyle mInvertedForegroundColorSpan; 272d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka private final CharacterStyle mInvertedBackgroundColorSpan; 273d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka private static final int AUTO_CORRECT_BOLD = 0x01; 274d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka private static final int AUTO_CORRECT_UNDERLINE = 0x02; 275d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka private static final int AUTO_CORRECT_INVERT = 0x04; 276d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka 27716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka private final TextPaint mPaint; 27874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka private final int mAutoCorrectHighlight; 27974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 280d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka private final ArrayList<CharSequence> mTexts = new ArrayList<CharSequence>(); 281d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka private SuggestedWords mSuggestedWords; 28274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 28316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka private int mCountInStrip; 28474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka // True if the mCountInStrip suggestions can fit in suggestion strip in equally divided 28574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka // width without squeezing the text. 28616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka private boolean mCanUseFixedWidthColumns; 28716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka private int mMaxWidth; 28816713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka private int mAvailableWidthForWords; 28916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka private int mConstantWidthForPaddings; 29016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka private int mVariableWidthForWords; 29116713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka private float mScaleX; 29274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 293d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka public SuggestionsStripParams(Context context, AttributeSet attrs, int defStyle, 29416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka List<TextView> words, List<View> dividers, List<TextView> infos, View control) { 29516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka super(words, dividers, infos, control); 296d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka final TypedArray a = context.obtainStyledAttributes( 297d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka attrs, R.styleable.CandidateView, defStyle, R.style.CandidateViewStyle); 298d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka mAutoCorrectHighlight = a.getInt(R.styleable.CandidateView_autoCorrectHighlight, 0); 299d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka mColorTypedWord = a.getColor(R.styleable.CandidateView_colorTypedWord, 0); 300d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka mColorAutoCorrect = a.getColor(R.styleable.CandidateView_colorAutoCorrect, 0); 301d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka mColorSuggestedCandidate = a.getColor(R.styleable.CandidateView_colorSuggested, 0); 302d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka mCandidateCountInStrip = a.getInt( 303d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka R.styleable.CandidateView_candidateCountInStrip, 304d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka DEFAULT_CANDIDATE_COUNT_IN_STRIP); 305d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka a.recycle(); 306d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka 307d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka mInvertedForegroundColorSpan = new ForegroundColorSpan(mColorTypedWord ^ 0x00ffffff); 308d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka mInvertedBackgroundColorSpan = new BackgroundColorSpan(mColorTypedWord); 309d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka 31074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mPaint = new TextPaint(); 311d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka final float textSize = context.getResources().getDimension(R.dimen.candidate_text_size); 31274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mPaint.setTextSize(textSize); 31374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka } 31474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 31516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka public int getTextColor() { 31616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka return mColorTypedWord; 317d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka } 318d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka 31916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka private CharSequence getStyledCandidateWord(CharSequence word, boolean isAutoCorrect) { 320d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka if (!isAutoCorrect) 321d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka return word; 322d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka final int len = word.length(); 323d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka final Spannable spannedWord = new SpannableString(word); 324d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka if ((mAutoCorrectHighlight & AUTO_CORRECT_BOLD) != 0) 325d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka spannedWord.setSpan(BOLD_SPAN, 0, len, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); 326d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka if ((mAutoCorrectHighlight & AUTO_CORRECT_UNDERLINE) != 0) 327d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka spannedWord.setSpan(UNDERLINE_SPAN, 0, len, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); 328d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka return spannedWord; 329d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka } 330d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka 33116713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka private int getWordPosition(int index) { 332d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka if (index >= 2) { 333d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka return index; 334d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka } 335d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka final boolean willAutoCorrect = !mSuggestedWords.mTypedWordValid 336d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka && mSuggestedWords.mHasMinimalSuggestion; 337d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka return willAutoCorrect ? 1 - index : index; 338d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka } 339d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka 34016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka private int getCandidateTextColor(int pos) { 341d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka final SuggestedWords suggestions = mSuggestedWords; 342d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka final boolean isAutoCorrect = suggestions.mHasMinimalSuggestion 343d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka && ((pos == 1 && !suggestions.mTypedWordValid) 344d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka || (pos == 0 && suggestions.mTypedWordValid)); 345d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka // TODO: Need to revisit this logic with bigram suggestions 346d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka final boolean isSuggestedCandidate = (pos != 0); 347d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka final boolean isPunctuationSuggestions = suggestions.isPunctuationSuggestions(); 348d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka 349d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka final int color; 350d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka if (isPunctuationSuggestions) { 351d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka color = mColorTypedWord; 352d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka } else if (isAutoCorrect) { 353d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka color = mColorAutoCorrect; 354d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka } else if (isSuggestedCandidate) { 355d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka color = mColorSuggestedCandidate; 356d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka } else { 357d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka color = mColorTypedWord; 358d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka } 359d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka final SuggestedWordInfo info = suggestions.getInfo(pos); 360d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka if (info != null && info.isPreviousSuggestedWord()) { 361d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka return applyAlpha(color, 0.5f); 362d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka } else { 363d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka return color; 364d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka } 365d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka } 366d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka 367d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka private static int applyAlpha(final int color, final float alpha) { 368d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka final int newAlpha = (int)(Color.alpha(color) * alpha); 369d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka return Color.argb(newAlpha, Color.red(color), Color.green(color), Color.blue(color)); 370d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka } 371d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka 372d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka public CharSequence getInvertedText(CharSequence text) { 373d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka if ((mAutoCorrectHighlight & AUTO_CORRECT_INVERT) == 0) 374d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka return null; 375d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka final int len = text.length(); 376d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka final Spannable word = new SpannableString(text); 377d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka word.setSpan(mInvertedBackgroundColorSpan, 0, len, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); 378d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka word.setSpan(mInvertedForegroundColorSpan, 0, len, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); 379d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka return word; 380d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka } 381d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka 38216713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka public int layout(SuggestedWords suggestions, ViewGroup stripView, ViewGroup paneView, 38316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka int stripWidth) { 384d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka mSuggestedWords = suggestions; 385d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka final int maxCount = suggestions.isPunctuationSuggestions() 386d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka ? PUNCTUATIONS_IN_STRIP : mCandidateCountInStrip; 38774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka final int size = suggestions.size(); 388d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka setupTexts(suggestions, size); 38974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mCountInStrip = Math.min(maxCount, size); 39074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mScaleX = 1.0f; 39116713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka calculateParameters(size, stripWidth); 39216713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka 39316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka int infoX = 0; 39416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka for (int index = 0; index < mCountInStrip; index++) { 39516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka final int pos = getWordPosition(index); 39616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka final TextView word = mWords.get(pos); 39716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka final View divider = mDividers.get(pos); 39816713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka final TextPaint paint = word.getPaint(); 39916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka // TODO: Reorder candidates in strip as appropriate. The center candidate should 40016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka // hold the word when space is typed (valid typed word or auto corrected word). 40116713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka word.setTextColor(getCandidateTextColor(pos)); 40216713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka final CharSequence styled = mTexts.get(pos); 40316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka 40416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka final TextView info; 40516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka if (DBG) { 40616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka final CharSequence debugInfo = getDebugInfo(mSuggestedWords, index); 40716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka if (debugInfo != null) { 40816713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka info = mInfos.get(index); 40916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka info.setText(debugInfo); 41016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka } else { 41116713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka info = null; 41216713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka } 41316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka } else { 41416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka info = null; 41516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka } 41674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 41716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka final CharSequence text; 41816713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka final float scaleX; 41916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka if (index == 0 && mCountInStrip == 1) { 42016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka text = getEllipsizedText(styled, mMaxWidth, paint); 42116713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka scaleX = paint.getTextScaleX(); 42216713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka } else { 42316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka text = styled; 42416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka scaleX = mScaleX; 42516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka } 42616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka word.setText(text); 42716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka word.setTextScaleX(scaleX); 42816713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka if (index != 0) { 42916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka // Add divider if this isn't the left most suggestion in candidate strip. 43016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka stripView.addView(divider); 43116713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka } 43216713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka stripView.addView(word); 43316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka if (mCanUseFixedWidthColumns) { 43416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka setLayoutWeight(word, 1.0f, mCandidateStripHeight); 43516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka } else { 43616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka final int width = getTextWidth(text, paint) + mPadding; 43716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka setLayoutWeight(word, width, mCandidateStripHeight); 43816713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka } 43916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka if (info != null) { 44016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka paneView.addView(info); 44116713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka info.measure(WRAP_CONTENT, WRAP_CONTENT); 44216713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka final int width = info.getMeasuredWidth(); 44316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka final int y = info.getMeasuredHeight(); 44416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka FrameLayoutCompatUtils.placeViewAt(info, infoX, 0, width, y); 44516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka infoX += width * 2; 44616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka } 44716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka } 44816713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka 44916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka return mCountInStrip; 45016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka } 45116713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka 45216713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka private void calculateParameters(int size, int maxWidth) { 45374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka do { 45474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mMaxWidth = maxWidth; 45574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka if (size > mCountInStrip) { 45674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mMaxWidth -= mControlWidth; 45774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka } 45874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 45974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka tryLayout(); 46074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 46174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka if (mCanUseFixedWidthColumns) { 46274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka return; 46374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka } 46474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka if (mVariableWidthForWords <= mAvailableWidthForWords) { 46574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka return; 46674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka } 46774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 46874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka final float scaleX = mAvailableWidthForWords / (float)mVariableWidthForWords; 46974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka if (scaleX >= MIN_TEXT_XSCALE) { 47074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mScaleX = scaleX; 47174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka return; 47274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka } 47374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 47474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mCountInStrip--; 47574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka } while (mCountInStrip > 1); 47674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka } 47774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 47816713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka private void tryLayout() { 47974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka final int maxCount = mCountInStrip; 48074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka final int dividers = mDividerWidth * (maxCount - 1); 481fe9b65afa84530d17dd82c770c19de763a50cb58Tadashi G. Takaoka mConstantWidthForPaddings = dividers + mPadding * maxCount; 48274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mAvailableWidthForWords = mMaxWidth - mConstantWidthForPaddings; 48374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 48474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mPaint.setTextScaleX(mScaleX); 485fe9b65afa84530d17dd82c770c19de763a50cb58Tadashi G. Takaoka final int maxFixedWidthForWord = (mMaxWidth - dividers) / maxCount - mPadding; 48674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mCanUseFixedWidthColumns = true; 48774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mVariableWidthForWords = 0; 48874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka for (int i = 0; i < maxCount; i++) { 48974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka final int width = getTextWidth(mTexts.get(i), mPaint); 49074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka if (width > maxFixedWidthForWord) 49174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mCanUseFixedWidthColumns = false; 49274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mVariableWidthForWords += width; 49374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka } 49474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka } 49574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 496d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka private void setupTexts(SuggestedWords suggestions, int count) { 49774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mTexts.clear(); 49874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka for (int i = 0; i < count; i++) { 499d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka final CharSequence word = suggestions.getWord(i); 50074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka final boolean isAutoCorrect = suggestions.mHasMinimalSuggestion 50174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka && ((i == 1 && !suggestions.mTypedWordValid) 50274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka || (i == 0 && suggestions.mTypedWordValid)); 503d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka final CharSequence styled = getStyledCandidateWord(word, isAutoCorrect); 50474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mTexts.add(styled); 50574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka } 50674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka } 50774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 50874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka @Override 50974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka public String toString() { 51074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka return String.format( 51174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka "count=%d width=%d avail=%d fixcol=%s scaleX=%4.2f const=%d var=%d", 51274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mCountInStrip, mMaxWidth, mAvailableWidthForWords, mCanUseFixedWidthColumns, 51374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mScaleX, mConstantWidthForPaddings, mVariableWidthForWords); 51474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka } 51574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka } 51674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 517923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 518923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Construct a CandidateView for showing suggested words for completion. 519923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * @param context 520923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * @param attrs 521923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 522923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public CandidateView(Context context, AttributeSet attrs) { 52308a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka this(context, attrs, R.attr.candidateViewStyle); 52408a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka } 52508a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka 52608a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka public CandidateView(Context context, AttributeSet attrs, int defStyle) { 527f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka // Note: Up to version 10 (Gingerbread) of the API, LinearLayout doesn't have 3-argument 528f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka // constructor. 529f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka // TODO: Call 3-argument constructor, super(context, attrs, defStyle), when we abandon 530f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka // backward compatibility with the version 10 or earlier of the API. 531f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka super(context, attrs); 532f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka if (defStyle != R.attr.candidateViewStyle) { 533f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka throw new IllegalArgumentException( 534f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka "can't accept defStyle other than R.attr.candidayeViewStyle: defStyle=" 535f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka + defStyle); 536f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka } 537f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka setBackgroundDrawable(LinearLayoutCompatUtils.getBackgroundDrawable( 538f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka context, attrs, defStyle, R.style.CandidateViewStyle)); 539923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 54016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka final LayoutInflater inflater = LayoutInflater.from(context); 54186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka inflater.inflate(R.layout.candidates_strip, this); 54286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka 54386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka mPreviewPopup = new PopupWindow(context); 544e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka mPreviewText = (TextView) inflater.inflate(R.layout.candidate_preview, null); 545e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka mPreviewPopup.setWindowLayoutMode(ViewGroup.LayoutParams.WRAP_CONTENT, 546e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka ViewGroup.LayoutParams.WRAP_CONTENT); 547923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project mPreviewPopup.setContentView(mPreviewText); 548923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project mPreviewPopup.setBackgroundDrawable(null); 549923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 55074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mCandidatesStrip = (ViewGroup)findViewById(R.id.candidates_strip); 551e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka for (int i = 0; i < MAX_SUGGESTIONS; i++) { 55274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka final TextView word = (TextView)inflater.inflate(R.layout.candidate_word, null); 5532442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka word.setTag(i); 5542442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka word.setOnClickListener(this); 5552442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka mWords.add(word); 556a1aab83a24e74cb0fad4b1c1e59b18d23ecbdad3Tadashi G. Takaoka final View divider = inflater.inflate(R.layout.candidate_divider, null); 557a1aab83a24e74cb0fad4b1c1e59b18d23ecbdad3Tadashi G. Takaoka divider.setTag(i); 558a1aab83a24e74cb0fad4b1c1e59b18d23ecbdad3Tadashi G. Takaoka divider.setOnClickListener(this); 559a1aab83a24e74cb0fad4b1c1e59b18d23ecbdad3Tadashi G. Takaoka mDividers.add(divider); 56074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mInfos.add((TextView)inflater.inflate(R.layout.candidate_info, null)); 561c9716b28ce438e06b5cacc07fc002944bcbe24a0Tadashi G. Takaoka } 562179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaoka 563717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka mTouchToSave = findViewById(R.id.touch_to_save); 564717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka mWordToSave = (TextView)findViewById(R.id.word_to_save); 565717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka mWordToSave.setOnClickListener(this); 566717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka 567e583371b13ebd9aa336d0883e8c174ae4918c758Tadashi G. Takaoka final TypedArray keyboardViewAttr = context.obtainStyledAttributes( 568e583371b13ebd9aa336d0883e8c174ae4918c758Tadashi G. Takaoka attrs, R.styleable.KeyboardView, R.attr.keyboardViewStyle, R.style.KeyboardView); 5697c57e3bda1ab1d8c5d5df7acb8aec8c089f9240bTadashi G. Takaoka final Drawable expandBackground = keyboardViewAttr.getDrawable( 5707c57e3bda1ab1d8c5d5df7acb8aec8c089f9240bTadashi G. Takaoka R.styleable.KeyboardView_keyBackground); 5717c57e3bda1ab1d8c5d5df7acb8aec8c089f9240bTadashi G. Takaoka final Drawable closeBackground = keyboardViewAttr.getDrawable( 572e583371b13ebd9aa336d0883e8c174ae4918c758Tadashi G. Takaoka R.styleable.KeyboardView_keyBackground); 573e583371b13ebd9aa336d0883e8c174ae4918c758Tadashi G. Takaoka final int keyTextColor = keyboardViewAttr.getColor( 574e583371b13ebd9aa336d0883e8c174ae4918c758Tadashi G. Takaoka R.styleable.KeyboardView_keyTextColor, 0xFF000000); 575e583371b13ebd9aa336d0883e8c174ae4918c758Tadashi G. Takaoka keyboardViewAttr.recycle(); 576e583371b13ebd9aa336d0883e8c174ae4918c758Tadashi G. Takaoka 57774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mCandidatesPaneControl = (ViewGroup)findViewById(R.id.candidates_pane_control); 57874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mExpandCandidatesPane = (TextView)findViewById(R.id.expand_candidates_pane); 5797c57e3bda1ab1d8c5d5df7acb8aec8c089f9240bTadashi G. Takaoka mExpandCandidatesPane.setBackgroundDrawable(expandBackground); 580e583371b13ebd9aa336d0883e8c174ae4918c758Tadashi G. Takaoka mExpandCandidatesPane.setTextColor(keyTextColor); 58186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka mExpandCandidatesPane.setOnClickListener(new OnClickListener() { 58286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka @Override 58386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka public void onClick(View view) { 58486e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka expandCandidatesPane(); 58586e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka } 58686e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka }); 58774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mCloseCandidatesPane = (TextView)findViewById(R.id.close_candidates_pane); 5887c57e3bda1ab1d8c5d5df7acb8aec8c089f9240bTadashi G. Takaoka mCloseCandidatesPane.setBackgroundDrawable(closeBackground); 589e583371b13ebd9aa336d0883e8c174ae4918c758Tadashi G. Takaoka mCloseCandidatesPane.setTextColor(keyTextColor); 59086e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka mCloseCandidatesPane.setOnClickListener(new OnClickListener() { 59186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka @Override 59286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka public void onClick(View view) { 59386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka closeCandidatesPane(); 59486e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka } 59586e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka }); 59674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mCandidatesPaneControl.measure(WRAP_CONTENT, WRAP_CONTENT); 59708a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka 598d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka mStripParams = new SuggestionsStripParams(context, attrs, defStyle, 59916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka mWords, mDividers, mInfos, mCandidatesPaneControl); 60016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka mPaneParams = new SuggestionsPaneParams( 60116713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka mWords, mDividers, mInfos, mCandidatesPaneControl); 602923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 603c9716b28ce438e06b5cacc07fc002944bcbe24a0Tadashi G. Takaoka 604923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 605c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka * A connection back to the input method. 606923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * @param listener 607923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 60886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka public void setListener(Listener listener, View inputView) { 609c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka mListener = listener; 61086e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka mKeyboardView = inputView.findViewById(R.id.keyboard_view); 611a7eed902f1b0d6871d416412b3c6f91163fa2578Tadashi G. Takaoka mCandidatesPane = FrameLayoutCompatUtils.getPlacer( 612a7eed902f1b0d6871d416412b3c6f91163fa2578Tadashi G. Takaoka (ViewGroup)inputView.findViewById(R.id.candidates_pane)); 61386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka mCandidatesPane.setOnClickListener(this); 61486e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka mCandidatesPaneContainer = (ViewGroup)inputView.findViewById( 61586e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka R.id.candidates_pane_container); 616923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 617923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 6187e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka public void setSuggestions(SuggestedWords suggestions) { 6199fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka if (suggestions == null) 620a15e45ef45931ba46678b39c159518d8aa2d4d65Tadashi G. Takaoka return; 6219fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka mSuggestions = suggestions; 6224edc7d074b174da447bbf28e62cfb914b236540eTadashi G. Takaoka mExpandCandidatesPane.setEnabled(false); 62355b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka if (mShowingAutoCorrectionInverted) { 6249fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka mHandler.postUpdateSuggestions(); 62555b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka } else { 6269fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka updateSuggestions(); 62755b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka } 62855b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka } 62955b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 6309fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka private void updateSuggestions() { 631e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka clear(); 63286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka closeCandidatesPane(); 63316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka if (mSuggestions.size() == 0) 63474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka return; 63574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 63616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka final int width = getWidth(); 63716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka final int countInStrip = mStripParams.layout( 63816713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka mSuggestions, mCandidatesStrip, mCandidatesPane, width); 63916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka final int countInPane = mPaneParams.layout( 64016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka mSuggestions, mCandidatesPane, countInStrip, mStripParams.getTextColor(), width); 64174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 64216713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka if (countInPane <= 0 && !DBG) { 64374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mCandidatesPaneControl.setVisibility(GONE); 64474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka } else { 64574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mCandidatesPaneControl.setVisibility(VISIBLE); 64674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mExpandCandidatesPane.setVisibility(VISIBLE); 6474edc7d074b174da447bbf28e62cfb914b236540eTadashi G. Takaoka mExpandCandidatesPane.setEnabled(true); 64874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka } 64916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka } 65074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 65116713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka private static CharSequence getDebugInfo(SuggestedWords suggestions, int pos) { 65216713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka if (DBG) { 65316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka final SuggestedWordInfo wordInfo = suggestions.getInfo(pos); 65416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka if (wordInfo != null) { 65516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka final CharSequence debugInfo = wordInfo.getDebugString(); 65616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka if (!TextUtils.isEmpty(debugInfo)) { 65716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka return debugInfo; 658d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka } 6592442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka } 66086e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka } 66116713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka return null; 66286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka } 66386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka 6643118277dd47492089761c0ed1097abaeb376395cTadashi G. Takaoka private static void setLayoutWeight(View v, float weight, int height) { 66574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka final ViewGroup.LayoutParams lp = v.getLayoutParams(); 66674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka if (lp instanceof LinearLayout.LayoutParams) { 66774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka final LinearLayout.LayoutParams llp = (LinearLayout.LayoutParams)lp; 66874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka llp.weight = weight; 66974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka llp.width = 0; 6703118277dd47492089761c0ed1097abaeb376395cTadashi G. Takaoka llp.height = height; 67174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka } 67274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka } 67374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 67416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka private static void centeringCandidates(ViewGroup parent, View from, View to, int width, 67516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka int parentWidth) { 67616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka final int fromIndex = parent.indexOfChild(from); 67716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka final int toIndex = parent.indexOfChild(to); 67816713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka final int offset = (parentWidth - width) / 2; 67986e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka for (int index = fromIndex; index <= toIndex; index++) { 68016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka offsetMargin(parent.getChildAt(index), offset, 0); 68186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka } 68286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka } 68386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka 68486e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka private static void offsetMargin(View v, int dx, int dy) { 685862e05a8f0aa03ddc4582d5bf68a3201f348cf1dTadashi G. Takaoka if (v == null) 686862e05a8f0aa03ddc4582d5bf68a3201f348cf1dTadashi G. Takaoka return; 6872442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka final ViewGroup.LayoutParams lp = v.getLayoutParams(); 68886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka if (lp instanceof ViewGroup.MarginLayoutParams) { 6892442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka final ViewGroup.MarginLayoutParams mlp = (ViewGroup.MarginLayoutParams)lp; 69086e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka mlp.setMargins(mlp.leftMargin + dx, mlp.topMargin + dy, 0, 0); 69186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka } 69286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka } 69386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka 69474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka private static CharSequence getEllipsizedText(CharSequence text, int maxWidth, 69574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka TextPaint paint) { 69674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka paint.setTextScaleX(1.0f); 69774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka final int width = getTextWidth(text, paint); 69874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka final float scaleX = Math.min(maxWidth / (float)width, 1.0f); 699b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka if (scaleX >= MIN_TEXT_XSCALE) { 70074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka paint.setTextScaleX(scaleX); 70174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka return text; 702b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka } 703b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka 70474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka // Note that TextUtils.ellipsize() use text-x-scale as 1.0 if ellipsize is needed. To get 70574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka // squeezed and ellipsezed text, passes enlarged width (maxWidth / MIN_TEXT_XSCALE). 70674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka final CharSequence ellipsized = TextUtils.ellipsize( 70774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka text, paint, maxWidth / MIN_TEXT_XSCALE, TextUtils.TruncateAt.MIDDLE); 70874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka paint.setTextScaleX(MIN_TEXT_XSCALE); 70974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka return ellipsized; 710b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka } 711b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka 71274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka private static int getTextWidth(CharSequence text, TextPaint paint) { 713b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka if (TextUtils.isEmpty(text)) return 0; 714fe9b65afa84530d17dd82c770c19de763a50cb58Tadashi G. Takaoka final Typeface savedTypeface = paint.getTypeface(); 71574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka paint.setTypeface(getTextTypeface(text)); 716b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka final int len = text.length(); 717b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka final float[] widths = new float[len]; 718b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka final int count = paint.getTextWidths(text, 0, len, widths); 719fe9b65afa84530d17dd82c770c19de763a50cb58Tadashi G. Takaoka int width = 0; 720b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka for (int i = 0; i < count; i++) { 721fe9b65afa84530d17dd82c770c19de763a50cb58Tadashi G. Takaoka width += Math.round(widths[i] + 0.5f); 722b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka } 723fe9b65afa84530d17dd82c770c19de763a50cb58Tadashi G. Takaoka paint.setTypeface(savedTypeface); 724fe9b65afa84530d17dd82c770c19de763a50cb58Tadashi G. Takaoka return width; 725b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka } 726b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka 72774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka private static Typeface getTextTypeface(CharSequence text) { 72874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka if (!(text instanceof SpannableString)) 72974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka return Typeface.DEFAULT; 73074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 73174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka final SpannableString ss = (SpannableString)text; 73274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka final StyleSpan[] styles = ss.getSpans(0, text.length(), StyleSpan.class); 73374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka if (styles.length == 0) 73474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka return Typeface.DEFAULT; 73574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 73674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka switch (styles[0].getStyle()) { 73774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka case Typeface.BOLD: return Typeface.DEFAULT_BOLD; 73874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka // TODO: BOLD_ITALIC, ITALIC case? 73974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka default: return Typeface.DEFAULT; 740b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka } 741b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka } 742b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka 74386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka private void expandCandidatesPane() { 74474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mExpandCandidatesPane.setVisibility(GONE); 74574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mCloseCandidatesPane.setVisibility(VISIBLE); 74686e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka mCandidatesPaneContainer.setMinimumHeight(mKeyboardView.getMeasuredHeight()); 74774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mCandidatesPaneContainer.setVisibility(VISIBLE); 74874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mKeyboardView.setVisibility(GONE); 74986e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka } 750e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka 75186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka private void closeCandidatesPane() { 75274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mExpandCandidatesPane.setVisibility(VISIBLE); 75374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mCloseCandidatesPane.setVisibility(GONE); 75474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mCandidatesPaneContainer.setVisibility(GONE); 75574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mKeyboardView.setVisibility(VISIBLE); 756923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 757923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 75855b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka public void onAutoCorrectionInverted(CharSequence autoCorrectedWord) { 759d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka final CharSequence inverted = mStripParams.getInvertedText(autoCorrectedWord); 760d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka if (inverted == null) 76155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka return; 7621e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka final TextView tv = mWords.get(1); 763d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka tv.setText(inverted); 76455b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka mShowingAutoCorrectionInverted = true; 76555b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka } 76655b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 767b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani public boolean isShowingAddToDictionaryHint() { 768b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani return mShowingAddToDictionary; 769b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani } 770b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani 77166a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani public void showAddToDictionaryHint(CharSequence word) { 772717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka mWordToSave.setText(word); 77366a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani mShowingAddToDictionary = true; 77474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mCandidatesStrip.setVisibility(GONE); 7755a931efe1e1e8fc0fe046dda1dc3a91e63504114Tadashi G. Takaoka mCandidatesPaneControl.setVisibility(GONE); 77674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mTouchToSave.setVisibility(VISIBLE); 77766a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani } 77866a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani 7796558253160e2039c87f424bd814f402ecd31de3bKen Wakasa public boolean dismissAddToDictionaryHint() { 7806558253160e2039c87f424bd814f402ecd31de3bKen Wakasa if (!mShowingAddToDictionary) return false; 7816558253160e2039c87f424bd814f402ecd31de3bKen Wakasa clear(); 7826558253160e2039c87f424bd814f402ecd31de3bKen Wakasa return true; 7836558253160e2039c87f424bd814f402ecd31de3bKen Wakasa } 7846558253160e2039c87f424bd814f402ecd31de3bKen Wakasa 7857e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka public SuggestedWords getSuggestions() { 786979f8690967ff5409fe18f5085858ccdb8e0ccf1satok return mSuggestions; 787979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 788979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 789923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public void clear() { 79066a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani mShowingAddToDictionary = false; 79155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka mShowingAutoCorrectionInverted = false; 79274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mTouchToSave.setVisibility(GONE); 7931bd62a56211db2933eb5dd735c108e610111d6fbKen Wakasa mCandidatesStrip.setVisibility(VISIBLE); 79474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mCandidatesStrip.removeAllViews(); 79586e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka mCandidatesPane.removeAllViews(); 79688110d1799146943c627916ffaa94bbc4dd6f2aeTadashi G. Takaoka closeCandidatesPane(); 797923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 798923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 7996ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani private void hidePreview() { 800179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaoka mPreviewPopup.dismiss(); 8016ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani } 802e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka 803e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka private void showPreview(int index, CharSequence word) { 804e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka if (TextUtils.isEmpty(word)) 805e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka return; 806e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka 807e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka final TextView previewText = mPreviewText; 808d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka previewText.setTextColor(mStripParams.mColorTypedWord); 809e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka previewText.setText(word); 810e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka previewText.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), 811e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); 812f20eb55d4f8063f89c6c0abb3af3029fe23cb845Tadashi G. Takaoka View v = mWords.get(index); 813e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka final int[] offsetInWindow = new int[2]; 814e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka v.getLocationInWindow(offsetInWindow); 815e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka final int posX = offsetInWindow[0]; 816e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka final int posY = offsetInWindow[1] - previewText.getMeasuredHeight(); 817e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka final PopupWindow previewPopup = mPreviewPopup; 818e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka if (previewPopup.isShowing()) { 819e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka previewPopup.update(posX, posY, previewPopup.getWidth(), previewPopup.getHeight()); 820e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka } else { 821e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka previewPopup.showAtLocation(this, Gravity.NO_GRAVITY, posX, posY); 822923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 823e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka previewText.setVisibility(VISIBLE); 82455b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka mHandler.postHidePreview(); 825923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 826fcba53ef7c874a4685c12c01404c91b779cae1e8Tadashi G. Takaoka 827e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka private void addToDictionary(CharSequence word) { 828c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka if (mListener.addWordToDictionary(word.toString())) { 829e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka showPreview(0, getContext().getString(R.string.added_word, word)); 830e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka } 831e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka } 832e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka 833e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka @Override 834e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka public void onClick(View view) { 835717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka if (view == mWordToSave) { 836717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka addToDictionary(((TextView)view).getText()); 837717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka clear(); 838717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka return; 839717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka } 840717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka 84186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka final Object tag = view.getTag(); 84286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka if (!(tag instanceof Integer)) 84386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka return; 84486e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka final int index = (Integer) tag; 84537deb112c727dfed5e94d054cf5f00f5d60c8120Tadashi G. Takaoka if (index >= mSuggestions.size()) 84637deb112c727dfed5e94d054cf5f00f5d60c8120Tadashi G. Takaoka return; 84786e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka 84837deb112c727dfed5e94d054cf5f00f5d60c8120Tadashi G. Takaoka final CharSequence word = mSuggestions.getWord(index); 849717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka mListener.pickSuggestionManually(index, word); 85086e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka // Because some punctuation letters are not treated as word separator depending on locale, 85186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka // {@link #setSuggestions} might not be called and candidates pane left opened. 85286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka closeCandidatesPane(); 853923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 85482411d47ba7e8133ed2390c6920945e139a738cesatok 8556ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani @Override 8566ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani public void onDetachedFromWindow() { 8576ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani super.onDetachedFromWindow(); 85855b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka mHandler.cancelAllMessages(); 8596ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani hidePreview(); 8606ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani } 861923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project} 862