SuggestionStripView.java revision 86e815a142c8aa13213151e381a8a24ef23073d3
1923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project/* 2e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka * Copyright (C) 2010 The Android Open Source Project 3e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka * 4923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * use this file except in compliance with the License. You may obtain a copy of 6923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * the License at 7e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka * 8923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 9e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka * 10923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 11923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * License for the specific language governing permissions and limitations under 14923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * the License. 15923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 16923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 17923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectpackage com.android.inputmethod.latin; 18923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 19923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.Context; 2066a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasaniimport android.content.res.Resources; 216f7218627eda110a8454053f8ecb7b80edfdc8cesatokimport android.graphics.Color; 22923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.graphics.Typeface; 23e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaokaimport android.os.Handler; 24e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaokaimport android.os.Message; 25522d5c16d20657e7d26009fe9c067404e16a6c2aTadashi G. Takaokaimport android.text.Spannable; 26522d5c16d20657e7d26009fe9c067404e16a6c2aTadashi G. Takaokaimport android.text.SpannableString; 27e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaokaimport android.text.Spanned; 28e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaokaimport android.text.TextUtils; 2955b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaokaimport android.text.style.BackgroundColorSpan; 30522d5c16d20657e7d26009fe9c067404e16a6c2aTadashi G. Takaokaimport android.text.style.CharacterStyle; 3155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaokaimport android.text.style.ForegroundColorSpan; 32522d5c16d20657e7d26009fe9c067404e16a6c2aTadashi G. Takaokaimport android.text.style.StyleSpan; 33522d5c16d20657e7d26009fe9c067404e16a6c2aTadashi G. Takaokaimport android.text.style.UnderlineSpan; 34923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.util.AttributeSet; 35923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.Gravity; 36923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.LayoutInflater; 37923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.View; 38e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaokaimport android.view.View.OnClickListener; 39e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaokaimport android.view.View.OnLongClickListener; 40e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaokaimport android.view.ViewGroup; 41e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaokaimport android.widget.LinearLayout; 42923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.widget.PopupWindow; 43923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.widget.TextView; 44923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 45ddb61ea461b920d87be4ad78c8a36eec1013b965Tadashi G. Takaokaimport com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; 46ddb61ea461b920d87be4ad78c8a36eec1013b965Tadashi G. Takaoka 47179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaokaimport java.util.ArrayList; 486f7218627eda110a8454053f8ecb7b80edfdc8cesatokimport java.util.List; 49179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaoka 50e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaokapublic class CandidateView extends LinearLayout implements OnClickListener, OnLongClickListener { 51923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 52c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka public interface Listener { 53c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka public boolean addWordToDictionary(String word); 54c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka public void pickSuggestionManually(int index, CharSequence word); 55c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka } 56c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka 5782411d47ba7e8133ed2390c6920945e139a738cesatok private static final CharacterStyle BOLD_SPAN = new StyleSpan(Typeface.BOLD); 5882411d47ba7e8133ed2390c6920945e139a738cesatok private static final CharacterStyle UNDERLINE_SPAN = new UnderlineSpan(); 5986e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka // The maximum number of suggestions available. See {@link Suggest#mPrefMaxSuggestions}. 6086e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka private static final int MAX_SUGGESTIONS = 18; 6186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka private static final int UNSPECIFIED_MEASURESPEC = MeasureSpec.makeMeasureSpec( 6286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka 0, MeasureSpec.UNSPECIFIED); 63923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 648553b5ec315660ab53dd9234e64e1e39ea09ec0fJean Chalard private static final boolean DBG = LatinImeLogger.sDBG; 656f7218627eda110a8454053f8ecb7b80edfdc8cesatok 6686e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka private static final int NUM_CANDIDATES_IN_STRIP = 3; 6786e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka private final View mExpandCandidatesPane; 6886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka private final View mCloseCandidatesPane; 6986e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka private ViewGroup mCandidatesPane; 7086e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka private ViewGroup mCandidatesPaneContainer; 7186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka private View mKeyboardView; 721e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka private final ArrayList<TextView> mWords = new ArrayList<TextView>(); 73ddb61ea461b920d87be4ad78c8a36eec1013b965Tadashi G. Takaoka private final ArrayList<View> mDividers = new ArrayList<View>(); 741e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka private final int mCandidatePadding; 7586e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka private final int mCandidateStripHeight; 76e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka private final boolean mConfigCandidateHighlightFontColorEnabled; 7782411d47ba7e8133ed2390c6920945e139a738cesatok private final CharacterStyle mInvertedForegroundColorSpan; 7882411d47ba7e8133ed2390c6920945e139a738cesatok private final CharacterStyle mInvertedBackgroundColorSpan; 791e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka private final int mColorTypedWord; 801e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka private final int mColorAutoCorrect; 811e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka private final int mColorSuggestedCandidate; 8282411d47ba7e8133ed2390c6920945e139a738cesatok private final PopupWindow mPreviewPopup; 8382411d47ba7e8133ed2390c6920945e139a738cesatok private final TextView mPreviewText; 8466a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani 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 9055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka private final UiHandler mHandler = new UiHandler(); 9155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 9255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka private class UiHandler extends Handler { 9355b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka private static final int MSG_HIDE_PREVIEW = 0; 9455b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka private static final int MSG_UPDATE_SUGGESTION = 1; 9555b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 9655b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka private static final long DELAY_HIDE_PREVIEW = 1000; 9755b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka private static final long DELAY_UPDATE_SUGGESTION = 300; 9855b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 99e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka @Override 100e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka public void dispatchMessage(Message msg) { 101e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka switch (msg.what) { 102e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka case MSG_HIDE_PREVIEW: 103e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka hidePreview(); 104e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka break; 10555b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka case MSG_UPDATE_SUGGESTION: 1069fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka updateSuggestions(); 10755b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka break; 108e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka } 109e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka } 11055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 11155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka public void postHidePreview() { 11255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka cancelHidePreview(); 11355b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka sendMessageDelayed(obtainMessage(MSG_HIDE_PREVIEW), DELAY_HIDE_PREVIEW); 11455b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka } 11555b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 11655b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka public void cancelHidePreview() { 11755b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka removeMessages(MSG_HIDE_PREVIEW); 11855b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka } 11955b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 1209fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka public void postUpdateSuggestions() { 12155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka cancelUpdateSuggestions(); 1229fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka sendMessageDelayed(obtainMessage(MSG_UPDATE_SUGGESTION), 12355b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka DELAY_UPDATE_SUGGESTION); 12455b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka } 12555b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 12655b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka public void cancelUpdateSuggestions() { 12755b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka removeMessages(MSG_UPDATE_SUGGESTION); 12855b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka } 12955b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 13055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka public void cancelAllMessages() { 13155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka cancelHidePreview(); 13255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka cancelUpdateSuggestions(); 13355b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka } 134e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka } 135179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaoka 136923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 137923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Construct a CandidateView for showing suggested words for completion. 138923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * @param context 139923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * @param attrs 140923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 141923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public CandidateView(Context context, AttributeSet attrs) { 142923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project super(context, attrs); 143923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 14466a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani Resources res = context.getResources(); 145e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka LayoutInflater inflater = LayoutInflater.from(context); 14686e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka inflater.inflate(R.layout.candidates_strip, this); 14786e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka 14886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka mPreviewPopup = new PopupWindow(context); 149e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka mPreviewText = (TextView) inflater.inflate(R.layout.candidate_preview, null); 150e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka mPreviewPopup.setWindowLayoutMode(ViewGroup.LayoutParams.WRAP_CONTENT, 151e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka ViewGroup.LayoutParams.WRAP_CONTENT); 152923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project mPreviewPopup.setContentView(mPreviewText); 153923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project mPreviewPopup.setBackgroundDrawable(null); 154e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka mConfigCandidateHighlightFontColorEnabled = 155e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka res.getBoolean(R.bool.config_candidate_highlight_font_color_enabled); 1561e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka mColorTypedWord = res.getColor(R.color.candidate_typed_word); 1571e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka mColorAutoCorrect = res.getColor(R.color.candidate_auto_correct); 1581e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka mColorSuggestedCandidate = res.getColor(R.color.candidate_suggested); 1591e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka mInvertedForegroundColorSpan = new ForegroundColorSpan(mColorTypedWord ^ 0x00ffffff); 1601e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka mInvertedBackgroundColorSpan = new BackgroundColorSpan(mColorTypedWord); 161923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 1621e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka mCandidatePadding = res.getDimensionPixelOffset(R.dimen.candidate_padding); 16386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka mCandidateStripHeight = res.getDimensionPixelOffset(R.dimen.candidate_strip_height); 164e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka for (int i = 0; i < MAX_SUGGESTIONS; i++) { 16586e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka final TextView tv; 16686e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka switch (i) { 16786e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka case 0: 16886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka tv = (TextView)findViewById(R.id.candidate_left); 16986e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka tv.setPadding(mCandidatePadding, 0, 0, 0); 17086e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka break; 17186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka case 1: 17286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka tv = (TextView)findViewById(R.id.candidate_center); 17386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka break; 17486e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka case 2: 17586e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka tv = (TextView)findViewById(R.id.candidate_right); 17686e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka break; 17786e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka default: 17886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka tv = (TextView)inflater.inflate(R.layout.candidate, null); 17986e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka break; 18086e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka } 18186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka if (i < NUM_CANDIDATES_IN_STRIP) 18286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka setLayoutWeight(tv, 1.0f); 183e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka tv.setTag(i); 184e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka tv.setOnClickListener(this); 185e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka if (i == 0) 186e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka tv.setOnLongClickListener(this); 1871e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka mWords.add(tv); 188ddb61ea461b920d87be4ad78c8a36eec1013b965Tadashi G. Takaoka if (i > 0) { 189070760dc5abdb9a850a94c509eeb9f486515af59Tadashi G. Takaoka final View divider = inflater.inflate(R.layout.candidate_divider, null); 19086e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka divider.measure(UNSPECIFIED_MEASURESPEC, UNSPECIFIED_MEASURESPEC); 191ddb61ea461b920d87be4ad78c8a36eec1013b965Tadashi G. Takaoka mDividers.add(divider); 192ddb61ea461b920d87be4ad78c8a36eec1013b965Tadashi G. Takaoka } 193c9716b28ce438e06b5cacc07fc002944bcbe24a0Tadashi G. Takaoka } 194179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaoka 19586e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka mExpandCandidatesPane = findViewById(R.id.expand_candidates_pane); 19686e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka mExpandCandidatesPane.setOnClickListener(new OnClickListener() { 19786e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka @Override 19886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka public void onClick(View view) { 19986e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka expandCandidatesPane(); 20086e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka } 20186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka }); 20286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka mCloseCandidatesPane = findViewById(R.id.close_candidates_pane); 20386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka mCloseCandidatesPane.setOnClickListener(new OnClickListener() { 20486e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka @Override 20586e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka public void onClick(View view) { 20686e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka closeCandidatesPane(); 20786e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka } 20886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka }); 209923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 210c9716b28ce438e06b5cacc07fc002944bcbe24a0Tadashi G. Takaoka 211923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 212c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka * A connection back to the input method. 213923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * @param listener 214923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 21586e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka public void setListener(Listener listener, View inputView) { 216c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka mListener = listener; 21786e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka mKeyboardView = inputView.findViewById(R.id.keyboard_view); 21886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka mCandidatesPane = (ViewGroup)inputView.findViewById(R.id.candidates_pane); 21986e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka mCandidatesPane.setOnClickListener(this); 22086e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka mCandidatesPaneContainer = (ViewGroup)inputView.findViewById( 22186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka R.id.candidates_pane_container); 222923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 223923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 2247e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka public void setSuggestions(SuggestedWords suggestions) { 2259fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka if (suggestions == null) 226a15e45ef45931ba46678b39c159518d8aa2d4d65Tadashi G. Takaoka return; 2279fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka mSuggestions = suggestions; 22855b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka if (mShowingAutoCorrectionInverted) { 2299fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka mHandler.postUpdateSuggestions(); 23055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka } else { 2319fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka updateSuggestions(); 23255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka } 23355b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka } 23455b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 23586e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka private static void setLayoutWeight(View v, float weight) { 23686e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka ViewGroup.LayoutParams lp = v.getLayoutParams(); 23786e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka if (lp instanceof LinearLayout.LayoutParams) { 23886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka LinearLayout.LayoutParams llp = (LinearLayout.LayoutParams)lp; 23986e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka llp.width = 0; 24086e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka llp.weight = weight; 24186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka } 24286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka } 24386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka 2441e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka private CharSequence getStyledCandidateWord(CharSequence word, boolean isAutoCorrect) { 2451e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka if (!isAutoCorrect) 2461e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka return word; 2471e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka final CharacterStyle style = mConfigCandidateHighlightFontColorEnabled ? BOLD_SPAN 2481e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka : UNDERLINE_SPAN; 2491e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka final Spannable spannedWord = new SpannableString(word); 2501e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka spannedWord.setSpan(style, 0, word.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE); 2511e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka return spannedWord; 2521e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka } 2531e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka 2541e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka private int getCandidateTextColor(boolean isAutoCorrect, boolean isSuggestedCandidate, 2551e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka SuggestedWordInfo info) { 2561e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka final int color; 2571e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka if (isAutoCorrect && mConfigCandidateHighlightFontColorEnabled) { 2581e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka color = mColorAutoCorrect; 259070760dc5abdb9a850a94c509eeb9f486515af59Tadashi G. Takaoka } else if (isSuggestedCandidate && mConfigCandidateHighlightFontColorEnabled) { 2601e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka color = mColorSuggestedCandidate; 2611e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka } else { 2621e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka color = mColorTypedWord; 2631e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka } 2641e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka if (info != null && info.isPreviousSuggestedWord()) { 2651e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka final int newAlpha = (int)(Color.alpha(color) * 0.5f); 2661e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka return Color.argb(newAlpha, Color.red(color), Color.green(color), Color.blue(color)); 2671e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka } else { 2681e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka return color; 2691e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka } 2701e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka } 2711e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka 2729fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka private void updateSuggestions() { 2739fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka final SuggestedWords suggestions = mSuggestions; 2741e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka final List<SuggestedWordInfo> suggestedWordInfoList = suggestions.mSuggestedWordInfoList; 2751e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka 276e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka clear(); 27786e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka final int paneWidth = getWidth(); 27886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka final int dividerWidth = mDividers.get(0).getMeasuredWidth(); 27986e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka int x = 0; 28086e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka int y = 0; 28186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka int fromIndex = NUM_CANDIDATES_IN_STRIP; 282ec5ae3a1b6ce6d6c87406def849995ec63816c55Ken Wakasa final int count = Math.min(mWords.size(), suggestions.size()); 28386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka closeCandidatesPane(); 28486e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka mExpandCandidatesPane.setEnabled(count >= NUM_CANDIDATES_IN_STRIP); 285923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project for (int i = 0; i < count; i++) { 2861e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka final CharSequence word = suggestions.getWord(i); 2877e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka if (word == null) continue; 2881e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka 2891e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka final SuggestedWordInfo info = (suggestedWordInfoList != null) 2901e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka ? suggestedWordInfoList.get(i) : null; 2911e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka final boolean isAutoCorrect = suggestions.mHasMinimalSuggestion 29282411d47ba7e8133ed2390c6920945e139a738cesatok && ((i == 1 && !suggestions.mTypedWordValid) 2931e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka || (i == 0 && suggestions.mTypedWordValid)); 2941e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka // HACK: even if i == 0, we use mColorOther when this suggestion's length is 1 2951e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka // and there are multiple suggestions, such as the default punctuation list. 2961e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka // TODO: Need to revisit this logic with bigram suggestions 2971e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka final boolean isSuggestedCandidate = (i != 0); 2981e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka final boolean isPunctuationSuggestions = (word.length() == 1 && count > 1); 2991e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka 3001e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka final TextView tv = mWords.get(i); 30186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka // TODO: Reorder candidates in strip as appropriate. The center candidate should hold 30286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka // the word when space is typed (valid typed word or auto corrected word). 3031e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka tv.setTextColor(getCandidateTextColor(isAutoCorrect, 3041e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka isSuggestedCandidate || isPunctuationSuggestions, info)); 3051e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka tv.setText(getStyledCandidateWord(word, isAutoCorrect)); 30686e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka // TODO: call TextView.setTextScaleX() to fit the candidate in single line. 30786e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka if (i >= NUM_CANDIDATES_IN_STRIP) { 30886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka tv.measure(UNSPECIFIED_MEASURESPEC, UNSPECIFIED_MEASURESPEC); 30986e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka final int width = tv.getMeasuredWidth(); 31086e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka // TODO: Handle overflow case. 31186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka if (dividerWidth + x + width >= paneWidth) { 31286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka centeringCandidates(fromIndex, i - 1, x, paneWidth); 31386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka x = 0; 31486e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka y += mCandidateStripHeight; 31586e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka fromIndex = i; 31686e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka } 31786e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka if (x != 0) { 31886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka final View divider = mDividers.get(i - NUM_CANDIDATES_IN_STRIP); 31986e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka mCandidatesPane.addView(divider); 32086e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka placeCandidateAt(divider, x, y); 32186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka x += dividerWidth; 32286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka } 32386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka mCandidatesPane.addView(tv); 32486e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka placeCandidateAt(tv, x, y); 32586e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka x += width; 3267e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka } 3271e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka 3281e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka if (DBG && info != null) { 3291e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka final TextView dv = new TextView(getContext(), null); 3301e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka dv.setTextSize(10.0f); 3311e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka dv.setTextColor(0xff808080); 3321e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka dv.setText(info.getDebugString()); 33386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka // TODO: debug view for candidate strip needed. 33486e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka mCandidatesPane.addView(dv); 3351e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)dv.getLayoutParams(); 3361e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka lp.gravity = Gravity.BOTTOM; 3371e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka } 338923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 33986e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka if (x != 0) { 34086e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka // Centering last candidates row. 34186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka centeringCandidates(fromIndex, count - 1, x, paneWidth); 34286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka } 34386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka } 34486e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka 34586e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka private void placeCandidateAt(View v, int x, int y) { 34686e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka ViewGroup.LayoutParams lp = v.getLayoutParams(); 34786e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka if (lp instanceof ViewGroup.MarginLayoutParams) { 34886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka ViewGroup.MarginLayoutParams mlp = (ViewGroup.MarginLayoutParams)lp; 34986e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka mlp.width = v.getMeasuredWidth(); 35086e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka mlp.height = v.getMeasuredHeight(); 35186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka mlp.setMargins(x, y + (mCandidateStripHeight - mlp.height) / 2, 0, 0); 35286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka } 35386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka } 35486e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka 35586e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka private void centeringCandidates(int from, int to, int width, int paneWidth) { 35686e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka final ViewGroup pane = mCandidatesPane; 35786e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka final int fromIndex = pane.indexOfChild(mWords.get(from)); 35886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka final int toIndex = pane.indexOfChild(mWords.get(to)); 35986e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka final int offset = (paneWidth - width) / 2; 36086e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka for (int index = fromIndex; index <= toIndex; index++) { 36186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka offsetMargin(pane.getChildAt(index), offset, 0); 36286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka } 36386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka } 36486e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka 36586e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka private static void offsetMargin(View v, int dx, int dy) { 36686e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka ViewGroup.LayoutParams lp = v.getLayoutParams(); 36786e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka if (lp instanceof ViewGroup.MarginLayoutParams) { 36886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka ViewGroup.MarginLayoutParams mlp = (ViewGroup.MarginLayoutParams)lp; 36986e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka mlp.setMargins(mlp.leftMargin + dx, mlp.topMargin + dy, 0, 0); 37086e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka } 37186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka } 37286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka 37386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka private void expandCandidatesPane() { 37486e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka mExpandCandidatesPane.setVisibility(View.GONE); 37586e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka mCloseCandidatesPane.setVisibility(View.VISIBLE); 37686e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka mCandidatesPaneContainer.setMinimumHeight(mKeyboardView.getMeasuredHeight()); 37786e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka mCandidatesPaneContainer.setVisibility(View.VISIBLE); 37886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka mKeyboardView.setVisibility(View.GONE); 37986e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka } 380e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka 38186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka private void closeCandidatesPane() { 38286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka mExpandCandidatesPane.setVisibility(View.VISIBLE); 38386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka mCloseCandidatesPane.setVisibility(View.GONE); 38486e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka mCandidatesPaneContainer.setVisibility(View.GONE); 38586e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka mKeyboardView.setVisibility(View.VISIBLE); 386923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 387923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 38855b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka public void onAutoCorrectionInverted(CharSequence autoCorrectedWord) { 38955b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka // Displaying auto corrected word as inverted is enabled only when highlighting candidate 39055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka // with color is disabled. 39155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka if (mConfigCandidateHighlightFontColorEnabled) 39255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka return; 3931e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka final TextView tv = mWords.get(1); 39455b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka final Spannable word = new SpannableString(autoCorrectedWord); 39555b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka final int wordLength = word.length(); 3968553b5ec315660ab53dd9234e64e1e39ea09ec0fJean Chalard word.setSpan(mInvertedBackgroundColorSpan, 0, wordLength, 3978553b5ec315660ab53dd9234e64e1e39ea09ec0fJean Chalard Spanned.SPAN_INCLUSIVE_EXCLUSIVE); 3988553b5ec315660ab53dd9234e64e1e39ea09ec0fJean Chalard word.setSpan(mInvertedForegroundColorSpan, 0, wordLength, 3998553b5ec315660ab53dd9234e64e1e39ea09ec0fJean Chalard Spanned.SPAN_INCLUSIVE_EXCLUSIVE); 40055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka tv.setText(word); 40155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka mShowingAutoCorrectionInverted = true; 40255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka } 40355b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 4047e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka public boolean isConfigCandidateHighlightFontColorEnabled() { 4057e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka return mConfigCandidateHighlightFontColorEnabled; 4067e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka } 4077e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka 408b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani public boolean isShowingAddToDictionaryHint() { 409b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani return mShowingAddToDictionary; 410b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani } 411b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani 41266a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani public void showAddToDictionaryHint(CharSequence word) { 4137e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka SuggestedWords.Builder builder = new SuggestedWords.Builder() 4147e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka .addWord(word) 4157e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka .addWord(getContext().getText(R.string.hint_add_to_dictionary)); 4167e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka setSuggestions(builder.build()); 41766a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani mShowingAddToDictionary = true; 418e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka // Disable R.string.hint_add_to_dictionary button 4191e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka TextView tv = mWords.get(1); 420e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka tv.setClickable(false); 42166a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani } 42266a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani 4236558253160e2039c87f424bd814f402ecd31de3bKen Wakasa public boolean dismissAddToDictionaryHint() { 4246558253160e2039c87f424bd814f402ecd31de3bKen Wakasa if (!mShowingAddToDictionary) return false; 4256558253160e2039c87f424bd814f402ecd31de3bKen Wakasa clear(); 4266558253160e2039c87f424bd814f402ecd31de3bKen Wakasa return true; 4276558253160e2039c87f424bd814f402ecd31de3bKen Wakasa } 4286558253160e2039c87f424bd814f402ecd31de3bKen Wakasa 4297e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka public SuggestedWords getSuggestions() { 430979f8690967ff5409fe18f5085858ccdb8e0ccf1satok return mSuggestions; 431979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 432979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 433923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public void clear() { 43466a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani mShowingAddToDictionary = false; 43555b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka mShowingAutoCorrectionInverted = false; 43686e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka for (int i = 0; i < NUM_CANDIDATES_IN_STRIP; i++) 43786e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka mWords.get(i).setText(null); 43886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka mCandidatesPane.removeAllViews(); 439923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 440923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 4416ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani private void hidePreview() { 442179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaoka mPreviewPopup.dismiss(); 4436ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani } 444e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka 445e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka private void showPreview(int index, CharSequence word) { 446e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka if (TextUtils.isEmpty(word)) 447e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka return; 448e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka 449e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka final TextView previewText = mPreviewText; 4501e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka previewText.setTextColor(mColorTypedWord); 451e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka previewText.setText(word); 452e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka previewText.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), 453e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); 454f20eb55d4f8063f89c6c0abb3af3029fe23cb845Tadashi G. Takaoka View v = mWords.get(index); 455e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka final int[] offsetInWindow = new int[2]; 456e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka v.getLocationInWindow(offsetInWindow); 457e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka final int posX = offsetInWindow[0]; 458e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka final int posY = offsetInWindow[1] - previewText.getMeasuredHeight(); 459e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka final PopupWindow previewPopup = mPreviewPopup; 460e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka if (previewPopup.isShowing()) { 461e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka previewPopup.update(posX, posY, previewPopup.getWidth(), previewPopup.getHeight()); 462e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka } else { 463e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka previewPopup.showAtLocation(this, Gravity.NO_GRAVITY, posX, posY); 464923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 465e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka previewText.setVisibility(VISIBLE); 46655b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka mHandler.postHidePreview(); 467923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 468fcba53ef7c874a4685c12c01404c91b779cae1e8Tadashi G. Takaoka 469e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka private void addToDictionary(CharSequence word) { 470c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka if (mListener.addWordToDictionary(word.toString())) { 471e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka showPreview(0, getContext().getString(R.string.added_word, word)); 472e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka } 473e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka } 474e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka 475e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka @Override 476e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka public boolean onLongClick(View view) { 47786e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka final Object tag = view.getTag(); 47886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka if (!(tag instanceof Integer)) 47986e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka return true; 48086e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka final int index = (Integer) tag; 48137deb112c727dfed5e94d054cf5f00f5d60c8120Tadashi G. Takaoka if (index >= mSuggestions.size()) 48237deb112c727dfed5e94d054cf5f00f5d60c8120Tadashi G. Takaoka return true; 48386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka 48437deb112c727dfed5e94d054cf5f00f5d60c8120Tadashi G. Takaoka final CharSequence word = mSuggestions.getWord(index); 485e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka if (word.length() < 2) 486e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka return false; 487e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka addToDictionary(word); 488e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka return true; 489e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka } 490e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka 491e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka @Override 492e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka public void onClick(View view) { 49386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka final Object tag = view.getTag(); 49486e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka if (!(tag instanceof Integer)) 49586e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka return; 49686e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka final int index = (Integer) tag; 49737deb112c727dfed5e94d054cf5f00f5d60c8120Tadashi G. Takaoka if (index >= mSuggestions.size()) 49837deb112c727dfed5e94d054cf5f00f5d60c8120Tadashi G. Takaoka return; 49986e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka 50037deb112c727dfed5e94d054cf5f00f5d60c8120Tadashi G. Takaoka final CharSequence word = mSuggestions.getWord(index); 501e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka if (mShowingAddToDictionary && index == 0) { 502e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka addToDictionary(word); 503e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka } else { 504c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka mListener.pickSuggestionManually(index, word); 505923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 50686e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka // Because some punctuation letters are not treated as word separator depending on locale, 50786e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka // {@link #setSuggestions} might not be called and candidates pane left opened. 50886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka closeCandidatesPane(); 509923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 51082411d47ba7e8133ed2390c6920945e139a738cesatok 5116ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani @Override 5126ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani public void onDetachedFromWindow() { 5136ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani super.onDetachedFromWindow(); 51455b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka mHandler.cancelAllMessages(); 5156ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani hidePreview(); 5166ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani } 517923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project} 518