SuggestionStripView.java revision 74b6897a12ec603ef835aaa77a01f0c32f49aa1c
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; 24e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaokaimport android.os.Message; 25522d5c16d20657e7d26009fe9c067404e16a6c2aTadashi G. Takaokaimport android.text.Spannable; 26522d5c16d20657e7d26009fe9c067404e16a6c2aTadashi G. Takaokaimport android.text.SpannableString; 27e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaokaimport android.text.Spanned; 28b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaokaimport android.text.TextPaint; 29e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaokaimport android.text.TextUtils; 3055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaokaimport android.text.style.BackgroundColorSpan; 31522d5c16d20657e7d26009fe9c067404e16a6c2aTadashi G. Takaokaimport android.text.style.CharacterStyle; 3255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaokaimport android.text.style.ForegroundColorSpan; 3374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaokaimport android.text.style.StyleSpan; 34522d5c16d20657e7d26009fe9c067404e16a6c2aTadashi G. Takaokaimport android.text.style.UnderlineSpan; 35923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.util.AttributeSet; 36923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.Gravity; 37923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.LayoutInflater; 38923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.View; 39e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaokaimport android.view.View.OnClickListener; 40e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaokaimport android.view.View.OnLongClickListener; 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 53e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaokapublic class CandidateView extends LinearLayout implements OnClickListener, OnLongClickListener { 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 6074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka private static final CharacterStyle BOLD_SPAN = new StyleSpan(Typeface.BOLD); 6182411d47ba7e8133ed2390c6920945e139a738cesatok private static final CharacterStyle UNDERLINE_SPAN = new UnderlineSpan(); 6286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka // The maximum number of suggestions available. See {@link Suggest#mPrefMaxSuggestions}. 6386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka private static final int MAX_SUGGESTIONS = 18; 6474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka private static final int MATCH_PARENT = ViewGroup.LayoutParams.MATCH_PARENT; 6574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka private static final int WRAP_CONTENT = ViewGroup.LayoutParams.WRAP_CONTENT; 66923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 678553b5ec315660ab53dd9234e64e1e39ea09ec0fJean Chalard private static final boolean DBG = LatinImeLogger.sDBG; 686f7218627eda110a8454053f8ecb7b80edfdc8cesatok 6974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka private final ViewGroup mCandidatesStrip; 7074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka private final int mCandidateCountInStrip; 7174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka private static final int DEFAULT_CANDIDATE_COUNT_IN_STRIP = 3; 7274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka private final ViewGroup mCandidatesPaneControl; 7374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka private final TextView mExpandCandidatesPane; 7474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka private final TextView mCloseCandidatesPane; 7586e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka private ViewGroup mCandidatesPane; 7686e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka private ViewGroup mCandidatesPaneContainer; 7786e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka private View mKeyboardView; 7874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 791e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka private final ArrayList<TextView> mWords = new ArrayList<TextView>(); 802442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka private final ArrayList<TextView> mInfos = new ArrayList<TextView>(); 81ddb61ea461b920d87be4ad78c8a36eec1013b965Tadashi G. Takaoka private final ArrayList<View> mDividers = new ArrayList<View>(); 8274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 8386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka private final int mCandidateStripHeight; 8482411d47ba7e8133ed2390c6920945e139a738cesatok private final CharacterStyle mInvertedForegroundColorSpan; 8582411d47ba7e8133ed2390c6920945e139a738cesatok private final CharacterStyle mInvertedBackgroundColorSpan; 8608a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka private final int mAutoCorrectHighlight; 8708a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka private static final int AUTO_CORRECT_BOLD = 0x01; 8808a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka private static final int AUTO_CORRECT_UNDERLINE = 0x02; 8908a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka private static final int AUTO_CORRECT_INVERT = 0x04; 901e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka private final int mColorTypedWord; 911e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka private final int mColorAutoCorrect; 921e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka private final int mColorSuggestedCandidate; 9374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka private final int mColorDivider; 9474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 9582411d47ba7e8133ed2390c6920945e139a738cesatok private final PopupWindow mPreviewPopup; 9682411d47ba7e8133ed2390c6920945e139a738cesatok private final TextView mPreviewText; 9766a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani 98717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka private final View mTouchToSave; 99717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka private final TextView mWordToSave; 100717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka 101c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka private Listener mListener; 1027e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka private SuggestedWords mSuggestions = SuggestedWords.EMPTY; 10355b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka private boolean mShowingAutoCorrectionInverted; 104e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka private boolean mShowingAddToDictionary; 1056a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani 10674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka private final CandidateViewLayoutParams mParams; 10774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka private static final int PUNCTUATIONS_IN_STRIP = 6; 10874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka private static final float MIN_TEXT_XSCALE = 0.8f; 109b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka 1104f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa private final UiHandler mHandler = new UiHandler(this); 11155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 1124f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa private static class UiHandler extends StaticInnerHandlerWrapper<CandidateView> { 11355b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka private static final int MSG_HIDE_PREVIEW = 0; 11455b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka private static final int MSG_UPDATE_SUGGESTION = 1; 11555b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 11655b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka private static final long DELAY_HIDE_PREVIEW = 1000; 11755b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka private static final long DELAY_UPDATE_SUGGESTION = 300; 11855b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 1194f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa public UiHandler(CandidateView outerInstance) { 1204f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa super(outerInstance); 1214f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa } 1224f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa 123e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka @Override 124e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka public void dispatchMessage(Message msg) { 1254f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa final CandidateView candidateView = getOuterInstance(); 126e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka switch (msg.what) { 127e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka case MSG_HIDE_PREVIEW: 1284f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa candidateView.hidePreview(); 129e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka break; 13055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka case MSG_UPDATE_SUGGESTION: 1314f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa candidateView.updateSuggestions(); 13255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka break; 133e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka } 134e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka } 13555b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 13655b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka public void postHidePreview() { 13755b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka cancelHidePreview(); 13855b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka sendMessageDelayed(obtainMessage(MSG_HIDE_PREVIEW), DELAY_HIDE_PREVIEW); 13955b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka } 14055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 14155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka public void cancelHidePreview() { 14255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka removeMessages(MSG_HIDE_PREVIEW); 14355b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka } 14455b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 1459fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka public void postUpdateSuggestions() { 14655b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka cancelUpdateSuggestions(); 1479fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka sendMessageDelayed(obtainMessage(MSG_UPDATE_SUGGESTION), 14855b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka DELAY_UPDATE_SUGGESTION); 14955b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka } 15055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 15155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka public void cancelUpdateSuggestions() { 15255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka removeMessages(MSG_UPDATE_SUGGESTION); 15355b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka } 15455b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 15555b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka public void cancelAllMessages() { 15655b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka cancelHidePreview(); 15755b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka cancelUpdateSuggestions(); 15855b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka } 159e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka } 160179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaoka 16174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka private static class CandidateViewLayoutParams { 16274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka public final TextPaint mPaint; 16374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka public final int mPadding; 16474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka public final int mDividerWidth; 16574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka public final int mDividerHeight; 16674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka public final int mControlWidth; 16774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka private final int mAutoCorrectHighlight; 16874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 16974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka public final ArrayList<CharSequence> mTexts = new ArrayList<CharSequence>(); 17074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 17174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka public int mCountInStrip; 17274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka // True if the mCountInStrip suggestions can fit in suggestion strip in equally divided 17374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka // width without squeezing the text. 17474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka public boolean mCanUseFixedWidthColumns; 17574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka public int mMaxWidth; 17674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka public int mAvailableWidthForWords; 17774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka public int mConstantWidthForPaddings; 17874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka public int mVariableWidthForWords; 17974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka public float mScaleX; 18074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 18174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka public CandidateViewLayoutParams(Resources res, View divider, View control, 18274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka int autoCorrectHighlight) { 18374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mPaint = new TextPaint(); 18474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka final float textSize = res.getDimension(R.dimen.candidate_text_size); 18574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mPaint.setTextSize(textSize); 18674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mPadding = res.getDimensionPixelSize(R.dimen.candidate_padding); 18774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mDividerWidth = divider.getMeasuredWidth(); 18874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mDividerHeight = divider.getMeasuredHeight(); 18974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mControlWidth = control.getMeasuredWidth(); 19074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mAutoCorrectHighlight = autoCorrectHighlight; 19174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka } 19274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 19374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka public void layoutStrip(SuggestedWords suggestions, int maxWidth, int maxCount) { 19474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka final int size = suggestions.size(); 19574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka setupTexts(suggestions, size, mAutoCorrectHighlight); 19674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mCountInStrip = Math.min(maxCount, size); 19774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mScaleX = 1.0f; 19874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 19974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka do { 20074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mMaxWidth = maxWidth; 20174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka if (size > mCountInStrip) { 20274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mMaxWidth -= mControlWidth; 20374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka } 20474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 20574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka tryLayout(); 20674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 20774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka if (mCanUseFixedWidthColumns) { 20874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka return; 20974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka } 21074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka if (mVariableWidthForWords <= mAvailableWidthForWords) { 21174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka return; 21274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka } 21374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 21474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka final float scaleX = mAvailableWidthForWords / (float)mVariableWidthForWords; 21574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka if (scaleX >= MIN_TEXT_XSCALE) { 21674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mScaleX = scaleX; 21774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka return; 21874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka } 21974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 22074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mCountInStrip--; 22174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka } while (mCountInStrip > 1); 22274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka } 22374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 22474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka public void tryLayout() { 22574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka final int maxCount = mCountInStrip; 22674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka final int dividers = mDividerWidth * (maxCount - 1); 22774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mConstantWidthForPaddings = dividers + mPadding * maxCount * 2; 22874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mAvailableWidthForWords = mMaxWidth - mConstantWidthForPaddings; 22974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 23074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mPaint.setTextScaleX(mScaleX); 23174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka final int maxFixedWidthForWord = (mMaxWidth - dividers) / maxCount - mPadding * 2; 23274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mCanUseFixedWidthColumns = true; 23374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mVariableWidthForWords = 0; 23474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka for (int i = 0; i < maxCount; i++) { 23574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka final int width = getTextWidth(mTexts.get(i), mPaint); 23674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka if (width > maxFixedWidthForWord) 23774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mCanUseFixedWidthColumns = false; 23874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mVariableWidthForWords += width; 23974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka } 24074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka } 24174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 24274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka private void setupTexts(SuggestedWords suggestions, int count, int autoCorrectHighlight) { 24374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mTexts.clear(); 24474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka for (int i = 0; i < count; i++) { 24574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka final CharSequence suggestion = suggestions.getWord(i); 24674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka if (suggestion == null) continue; 24774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 24874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka final boolean isAutoCorrect = suggestions.mHasMinimalSuggestion 24974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka && ((i == 1 && !suggestions.mTypedWordValid) 25074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka || (i == 0 && suggestions.mTypedWordValid)); 25174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka // HACK: even if i == 0, we use mColorOther when this suggestion's length is 1 25274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka // and there are multiple suggestions, such as the default punctuation list. 25374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka // TODO: Need to revisit this logic with bigram suggestions 25474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka final CharSequence styled = getStyledCandidateWord(suggestion, isAutoCorrect, 25574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka autoCorrectHighlight); 25674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mTexts.add(styled); 25774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka } 25874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka } 25974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 26074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka @Override 26174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka public String toString() { 26274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka return String.format( 26374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka "count=%d width=%d avail=%d fixcol=%s scaleX=%4.2f const=%d var=%d", 26474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mCountInStrip, mMaxWidth, mAvailableWidthForWords, mCanUseFixedWidthColumns, 26574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mScaleX, mConstantWidthForPaddings, mVariableWidthForWords); 26674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka } 26774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka } 26874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 269923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 270923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Construct a CandidateView for showing suggested words for completion. 271923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * @param context 272923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * @param attrs 273923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 274923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public CandidateView(Context context, AttributeSet attrs) { 27508a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka this(context, attrs, R.attr.candidateViewStyle); 27608a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka } 27708a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka 27808a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka public CandidateView(Context context, AttributeSet attrs, int defStyle) { 279f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka // Note: Up to version 10 (Gingerbread) of the API, LinearLayout doesn't have 3-argument 280f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka // constructor. 281f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka // TODO: Call 3-argument constructor, super(context, attrs, defStyle), when we abandon 282f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka // backward compatibility with the version 10 or earlier of the API. 283f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka super(context, attrs); 284f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka if (defStyle != R.attr.candidateViewStyle) { 285f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka throw new IllegalArgumentException( 286f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka "can't accept defStyle other than R.attr.candidayeViewStyle: defStyle=" 287f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka + defStyle); 288f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka } 289f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka setBackgroundDrawable(LinearLayoutCompatUtils.getBackgroundDrawable( 290f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka context, attrs, defStyle, R.style.CandidateViewStyle)); 291923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 29274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka final TypedArray a = context.obtainStyledAttributes( 29374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka attrs, R.styleable.CandidateView, defStyle, R.style.CandidateViewStyle); 29474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mAutoCorrectHighlight = a.getInt(R.styleable.CandidateView_autoCorrectHighlight, 0); 29574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mColorTypedWord = a.getColor(R.styleable.CandidateView_colorTypedWord, 0); 29674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mColorAutoCorrect = a.getColor(R.styleable.CandidateView_colorAutoCorrect, 0); 29774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mColorSuggestedCandidate = a.getColor(R.styleable.CandidateView_colorSuggested, 0); 29874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mColorDivider = a.getColor(R.styleable.CandidateView_colorDivider, 0); 29974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mCandidateCountInStrip = a.getInt( 30074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka R.styleable.CandidateView_candidateCountInStrip, DEFAULT_CANDIDATE_COUNT_IN_STRIP); 30174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka a.recycle(); 30274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 30366a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani Resources res = context.getResources(); 304e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka LayoutInflater inflater = LayoutInflater.from(context); 30586e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka inflater.inflate(R.layout.candidates_strip, this); 30686e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka 30786e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka mPreviewPopup = new PopupWindow(context); 308e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka mPreviewText = (TextView) inflater.inflate(R.layout.candidate_preview, null); 309e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka mPreviewPopup.setWindowLayoutMode(ViewGroup.LayoutParams.WRAP_CONTENT, 310e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka ViewGroup.LayoutParams.WRAP_CONTENT); 311923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project mPreviewPopup.setContentView(mPreviewText); 312923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project mPreviewPopup.setBackgroundDrawable(null); 313923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 31474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mCandidatesStrip = (ViewGroup)findViewById(R.id.candidates_strip); 31586e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka mCandidateStripHeight = res.getDimensionPixelOffset(R.dimen.candidate_strip_height); 316e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka for (int i = 0; i < MAX_SUGGESTIONS; i++) { 31774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka final TextView word = (TextView)inflater.inflate(R.layout.candidate_word, null); 3182442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka word.setTag(i); 3192442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka word.setOnClickListener(this); 320e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka if (i == 0) 3212442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka word.setOnLongClickListener(this); 3222442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka mWords.add(word); 32374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mInfos.add((TextView)inflater.inflate(R.layout.candidate_info, null)); 32474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mDividers.add(getDivider(inflater)); 325c9716b28ce438e06b5cacc07fc002944bcbe24a0Tadashi G. Takaoka } 326179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaoka 327717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka mTouchToSave = findViewById(R.id.touch_to_save); 328717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka mWordToSave = (TextView)findViewById(R.id.word_to_save); 329717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka mWordToSave.setOnClickListener(this); 330717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka 33108a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka mInvertedForegroundColorSpan = new ForegroundColorSpan(mColorTypedWord ^ 0x00ffffff); 33208a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka mInvertedBackgroundColorSpan = new BackgroundColorSpan(mColorTypedWord); 33308a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka 33474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mCandidatesPaneControl = (ViewGroup)findViewById(R.id.candidates_pane_control); 33574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mExpandCandidatesPane = (TextView)findViewById(R.id.expand_candidates_pane); 33686e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka mExpandCandidatesPane.setOnClickListener(new OnClickListener() { 33786e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka @Override 33886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka public void onClick(View view) { 33986e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka expandCandidatesPane(); 34086e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka } 34186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka }); 34274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mCloseCandidatesPane = (TextView)findViewById(R.id.close_candidates_pane); 34386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka mCloseCandidatesPane.setOnClickListener(new OnClickListener() { 34486e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka @Override 34586e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka public void onClick(View view) { 34686e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka closeCandidatesPane(); 34786e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka } 34886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka }); 34974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mCandidatesPaneControl.measure(WRAP_CONTENT, WRAP_CONTENT); 35008a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka 35174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mParams = new CandidateViewLayoutParams(res, mDividers.get(0), mCandidatesPaneControl, 35274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mAutoCorrectHighlight); 35374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka } 35474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 35574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka private View getDivider(LayoutInflater inflater) { 35674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka final TextView divider = (TextView)inflater.inflate(R.layout.candidate_divider, null); 35774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka divider.setTextColor(mColorDivider); 35874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka divider.measure(WRAP_CONTENT, WRAP_CONTENT); 35974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka return divider; 360923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 361c9716b28ce438e06b5cacc07fc002944bcbe24a0Tadashi G. Takaoka 362923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 363c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka * A connection back to the input method. 364923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * @param listener 365923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 36686e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka public void setListener(Listener listener, View inputView) { 367c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka mListener = listener; 36886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka mKeyboardView = inputView.findViewById(R.id.keyboard_view); 369a7eed902f1b0d6871d416412b3c6f91163fa2578Tadashi G. Takaoka mCandidatesPane = FrameLayoutCompatUtils.getPlacer( 370a7eed902f1b0d6871d416412b3c6f91163fa2578Tadashi G. Takaoka (ViewGroup)inputView.findViewById(R.id.candidates_pane)); 37186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka mCandidatesPane.setOnClickListener(this); 37286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka mCandidatesPaneContainer = (ViewGroup)inputView.findViewById( 37386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka R.id.candidates_pane_container); 374923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 375923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 3767e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka public void setSuggestions(SuggestedWords suggestions) { 3779fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka if (suggestions == null) 378a15e45ef45931ba46678b39c159518d8aa2d4d65Tadashi G. Takaoka return; 3799fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka mSuggestions = suggestions; 38055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka if (mShowingAutoCorrectionInverted) { 3819fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka mHandler.postUpdateSuggestions(); 38255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka } else { 3839fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka updateSuggestions(); 38455b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka } 38555b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka } 38655b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 38774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka private static CharSequence getStyledCandidateWord(CharSequence word, boolean isAutoCorrect, 38874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka int autoCorrectHighlight) { 3891e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka if (!isAutoCorrect) 3901e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka return word; 3911e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka final Spannable spannedWord = new SpannableString(word); 39274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka if ((autoCorrectHighlight & AUTO_CORRECT_BOLD) != 0) 39374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka spannedWord.setSpan(BOLD_SPAN, 0, word.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE); 39474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka if ((autoCorrectHighlight & AUTO_CORRECT_UNDERLINE) != 0) 39508a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka spannedWord.setSpan(UNDERLINE_SPAN, 0, word.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE); 3961e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka return spannedWord; 3971e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka } 3981e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka 3991e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka private int getCandidateTextColor(boolean isAutoCorrect, boolean isSuggestedCandidate, 4001e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka SuggestedWordInfo info) { 4011e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka final int color; 40208a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka if (isAutoCorrect) { 4031e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka color = mColorAutoCorrect; 40408a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka } else if (isSuggestedCandidate) { 4051e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka color = mColorSuggestedCandidate; 4061e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka } else { 4071e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka color = mColorTypedWord; 4081e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka } 4091e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka if (info != null && info.isPreviousSuggestedWord()) { 4101e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka final int newAlpha = (int)(Color.alpha(color) * 0.5f); 4111e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka return Color.argb(newAlpha, Color.red(color), Color.green(color), Color.blue(color)); 4121e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka } else { 4131e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka return color; 4141e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka } 4151e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka } 4161e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka 4179fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka private void updateSuggestions() { 4189fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka final SuggestedWords suggestions = mSuggestions; 4191e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka final List<SuggestedWordInfo> suggestedWordInfoList = suggestions.mSuggestedWordInfoList; 42074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka final int paneWidth = getWidth(); 42174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka final CandidateViewLayoutParams params = mParams; 4221e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka 423e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka clear(); 42486e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka closeCandidatesPane(); 42574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka if (suggestions.size() == 0) 42674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka return; 42774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 42874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka params.layoutStrip(suggestions, paneWidth, suggestions.isPunctuationSuggestions() 42974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka ? PUNCTUATIONS_IN_STRIP : mCandidateCountInStrip); 43074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 43174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka final int count = Math.min(mWords.size(), suggestions.size()); 43274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka if (count <= params.mCountInStrip) { 43374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mCandidatesPaneControl.setVisibility(GONE); 43474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka } else { 43574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mCandidatesPaneControl.setVisibility(VISIBLE); 43674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mExpandCandidatesPane.setVisibility(VISIBLE); 43774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka } 43874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 43974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka final int countInStrip = params.mCountInStrip; 44074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka int fromIndex = countInStrip; 44174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka int x = 0, y = 0; 442923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project for (int i = 0; i < count; i++) { 44374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka final int pos; 44474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka if (i <= 1) { 44574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka final boolean willAutoCorrect = !suggestions.mTypedWordValid 44674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka && suggestions.mHasMinimalSuggestion; 44774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka pos = willAutoCorrect ? 1 - i : i; 44874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka } else { 44974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka pos = i; 45074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka } 45174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka final CharSequence suggestion = suggestions.getWord(pos); 4522442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka if (suggestion == null) continue; 4531e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka 4542442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka final SuggestedWordInfo suggestionInfo = (suggestedWordInfoList != null) 45574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka ? suggestedWordInfoList.get(pos) : null; 4561e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka final boolean isAutoCorrect = suggestions.mHasMinimalSuggestion 45774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka && ((pos == 1 && !suggestions.mTypedWordValid) 45874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka || (pos == 0 && suggestions.mTypedWordValid)); 4591e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka // HACK: even if i == 0, we use mColorOther when this suggestion's length is 1 4601e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka // and there are multiple suggestions, such as the default punctuation list. 4611e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka // TODO: Need to revisit this logic with bigram suggestions 46274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka final boolean isSuggestedCandidate = (pos != 0); 4632442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka final boolean isPunctuationSuggestions = (suggestion.length() == 1 && count > 1); 4641e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka 46574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka final TextView word = mWords.get(pos); 46674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka final TextPaint paint = word.getPaint(); 46786e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka // TODO: Reorder candidates in strip as appropriate. The center candidate should hold 46886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka // the word when space is typed (valid typed word or auto corrected word). 4692442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka word.setTextColor(getCandidateTextColor(isAutoCorrect, 4702442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka isSuggestedCandidate || isPunctuationSuggestions, suggestionInfo)); 47174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka final CharSequence styled = params.mTexts.get(pos); 4722442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka 4732442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka final TextView info; 4742442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka if (DBG && suggestionInfo != null 4752442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka && !TextUtils.isEmpty(suggestionInfo.getDebugString())) { 4762442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka info = mInfos.get(i); 4772442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka info.setText(suggestionInfo.getDebugString()); 4782442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka } else { 4792442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka info = null; 4802442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka } 4812442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka 48274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka final CharSequence text; 48374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka final float scaleX; 48474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka if (i < countInStrip) { 48574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka if (i == 0 && params.mCountInStrip == 1) { 48674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka text = getEllipsizedText(styled, params.mMaxWidth, paint); 48774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka scaleX = paint.getTextScaleX(); 48874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka } else { 48974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka text = styled; 49074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka scaleX = params.mScaleX; 49174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka } 49274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka word.setText(text); 49374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka word.setTextScaleX(scaleX); 49474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka if (i != 0) { 49574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka // Add divider if this isn't the left most suggestion in candidate strip. 49674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mCandidatesStrip.addView(mDividers.get(i)); 49774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka } 49874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mCandidatesStrip.addView(word); 49974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka if (params.mCanUseFixedWidthColumns) { 50074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka setLayoutWeight(word, 1.0f); 50174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka } else { 50274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka final int width = getTextWidth(text, paint) + params.mPadding * 2; 50374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka setLayoutWeight(word, width); 50474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka } 5052442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka if (info != null) { 50674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka word.measure(WRAP_CONTENT, MATCH_PARENT); 507b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka final int width = word.getMeasuredWidth(); 50874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka info.measure(WRAP_CONTENT, WRAP_CONTENT); 5092442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka final int infoWidth = info.getMeasuredWidth(); 5102442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka FrameLayoutCompatUtils.placeViewAt( 5117fb04fe007a6d0489168e9c87771db554c873464Tadashi G. Takaoka info, width - infoWidth, 0, infoWidth, info.getMeasuredHeight()); 5122442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka } 5132442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka } else { 51474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka paint.setTextScaleX(1.0f); 51574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka final int textWidth = getTextWidth(styled, paint); 51674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka int available = paneWidth - x - params.mPadding * 2; 51774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka if (textWidth >= available) { 51874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka // Needs new row, centering previous row. 51986e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka centeringCandidates(fromIndex, i - 1, x, paneWidth); 52086e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka x = 0; 52186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka y += mCandidateStripHeight; 52286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka fromIndex = i; 52386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka } 52486e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka if (x != 0) { 52574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka // Add divider if this isn't the left most suggestion in current row. 52674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka final View divider = mDividers.get(i); 5272442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka mCandidatesPane.addView(divider); 5282442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka FrameLayoutCompatUtils.placeViewAt( 52974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka divider, x, y + (mCandidateStripHeight - params.mDividerHeight) / 2, 53074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka params.mDividerWidth, params.mDividerHeight); 53174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka x += params.mDividerWidth; 53286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka } 53374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka available = paneWidth - x - params.mPadding * 2; 53474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka text = getEllipsizedText(styled, available, paint); 53574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka scaleX = paint.getTextScaleX(); 53674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka word.setText(text); 53774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka word.setTextScaleX(scaleX); 5382442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka mCandidatesPane.addView(word); 53974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka word.measure(WRAP_CONTENT, WRAP_CONTENT); 54074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka final int width = word.getMeasuredWidth(); 54174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka final int height = word.getMeasuredHeight(); 5422442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka FrameLayoutCompatUtils.placeViewAt( 5432442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka word, x, y + (mCandidateStripHeight - height) / 2, width, height); 5442442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka if (info != null) { 5452442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka mCandidatesPane.addView(info); 54674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka info.measure(WRAP_CONTENT, WRAP_CONTENT); 5472442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka final int infoWidth = info.getMeasuredWidth(); 5482442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka FrameLayoutCompatUtils.placeViewAt( 5492442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka info, x + width - infoWidth, y, infoWidth, info.getMeasuredHeight()); 5502442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka } 55186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka x += width; 5527e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka } 553923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 55486e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka if (x != 0) { 55586e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka // Centering last candidates row. 55686e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka centeringCandidates(fromIndex, count - 1, x, paneWidth); 55786e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka } 55886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka } 55986e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka 56074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka private static void setLayoutWeight(View v, float weight) { 56174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka final ViewGroup.LayoutParams lp = v.getLayoutParams(); 56274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka if (lp instanceof LinearLayout.LayoutParams) { 56374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka final LinearLayout.LayoutParams llp = (LinearLayout.LayoutParams)lp; 56474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka llp.weight = weight; 56574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka llp.width = 0; 56674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka llp.height = MATCH_PARENT; 56774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka } 56874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka } 56974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 57086e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka private void centeringCandidates(int from, int to, int width, int paneWidth) { 57186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka final ViewGroup pane = mCandidatesPane; 57286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka final int fromIndex = pane.indexOfChild(mWords.get(from)); 5732442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka final int toIndex; 5742442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka if (mInfos.get(to).getParent() != null) { 5752442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka toIndex = pane.indexOfChild(mInfos.get(to)); 5762442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka } else { 5772442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka toIndex = pane.indexOfChild(mWords.get(to)); 5782442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka } 57986e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka final int offset = (paneWidth - width) / 2; 58086e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka for (int index = fromIndex; index <= toIndex; index++) { 58186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka offsetMargin(pane.getChildAt(index), offset, 0); 58286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka } 58386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka } 58486e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka 58586e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka private static void offsetMargin(View v, int dx, int dy) { 586862e05a8f0aa03ddc4582d5bf68a3201f348cf1dTadashi G. Takaoka if (v == null) 587862e05a8f0aa03ddc4582d5bf68a3201f348cf1dTadashi G. Takaoka return; 5882442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka final ViewGroup.LayoutParams lp = v.getLayoutParams(); 58986e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka if (lp instanceof ViewGroup.MarginLayoutParams) { 5902442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka final ViewGroup.MarginLayoutParams mlp = (ViewGroup.MarginLayoutParams)lp; 59186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka mlp.setMargins(mlp.leftMargin + dx, mlp.topMargin + dy, 0, 0); 59286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka } 59386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka } 59486e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka 59574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka private static CharSequence getEllipsizedText(CharSequence text, int maxWidth, 59674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka TextPaint paint) { 59774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka paint.setTextScaleX(1.0f); 59874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka final int width = getTextWidth(text, paint); 59974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka final float scaleX = Math.min(maxWidth / (float)width, 1.0f); 600b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka if (scaleX >= MIN_TEXT_XSCALE) { 60174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka paint.setTextScaleX(scaleX); 60274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka return text; 603b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka } 604b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka 60574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka // Note that TextUtils.ellipsize() use text-x-scale as 1.0 if ellipsize is needed. To get 60674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka // squeezed and ellipsezed text, passes enlarged width (maxWidth / MIN_TEXT_XSCALE). 60774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka final CharSequence ellipsized = TextUtils.ellipsize( 60874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka text, paint, maxWidth / MIN_TEXT_XSCALE, TextUtils.TruncateAt.MIDDLE); 60974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka paint.setTextScaleX(MIN_TEXT_XSCALE); 61074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka return ellipsized; 611b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka } 612b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka 61374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka private static int getTextWidth(CharSequence text, TextPaint paint) { 614b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka if (TextUtils.isEmpty(text)) return 0; 61574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka paint.setTypeface(getTextTypeface(text)); 616b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka final int len = text.length(); 617b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka final float[] widths = new float[len]; 618b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka final int count = paint.getTextWidths(text, 0, len, widths); 619b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka float width = 0; 620b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka for (int i = 0; i < count; i++) { 621b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka width += widths[i]; 622b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka } 623b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka return (int)Math.round(width + 0.5); 624b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka } 625b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka 62674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka private static Typeface getTextTypeface(CharSequence text) { 62774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka if (!(text instanceof SpannableString)) 62874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka return Typeface.DEFAULT; 62974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 63074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka final SpannableString ss = (SpannableString)text; 63174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka final StyleSpan[] styles = ss.getSpans(0, text.length(), StyleSpan.class); 63274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka if (styles.length == 0) 63374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka return Typeface.DEFAULT; 63474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 63574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka switch (styles[0].getStyle()) { 63674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka case Typeface.BOLD: return Typeface.DEFAULT_BOLD; 63774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka // TODO: BOLD_ITALIC, ITALIC case? 63874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka default: return Typeface.DEFAULT; 639b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka } 640b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka } 641b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka 64286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka private void expandCandidatesPane() { 64374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mExpandCandidatesPane.setVisibility(GONE); 64474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mCloseCandidatesPane.setVisibility(VISIBLE); 64586e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka mCandidatesPaneContainer.setMinimumHeight(mKeyboardView.getMeasuredHeight()); 64674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mCandidatesPaneContainer.setVisibility(VISIBLE); 64774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mKeyboardView.setVisibility(GONE); 64886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka } 649e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka 65086e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka private void closeCandidatesPane() { 65174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mExpandCandidatesPane.setVisibility(VISIBLE); 65274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mCloseCandidatesPane.setVisibility(GONE); 65374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mCandidatesPaneContainer.setVisibility(GONE); 65474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mKeyboardView.setVisibility(VISIBLE); 655923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 656923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 65755b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka public void onAutoCorrectionInverted(CharSequence autoCorrectedWord) { 65808a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka if ((mAutoCorrectHighlight & AUTO_CORRECT_INVERT) == 0) 65955b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka return; 6601e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka final TextView tv = mWords.get(1); 66155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka final Spannable word = new SpannableString(autoCorrectedWord); 66255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka final int wordLength = word.length(); 6638553b5ec315660ab53dd9234e64e1e39ea09ec0fJean Chalard word.setSpan(mInvertedBackgroundColorSpan, 0, wordLength, 6648553b5ec315660ab53dd9234e64e1e39ea09ec0fJean Chalard Spanned.SPAN_INCLUSIVE_EXCLUSIVE); 6658553b5ec315660ab53dd9234e64e1e39ea09ec0fJean Chalard word.setSpan(mInvertedForegroundColorSpan, 0, wordLength, 6668553b5ec315660ab53dd9234e64e1e39ea09ec0fJean Chalard Spanned.SPAN_INCLUSIVE_EXCLUSIVE); 66755b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka tv.setText(word); 66855b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka mShowingAutoCorrectionInverted = true; 66955b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka } 67055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 671b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani public boolean isShowingAddToDictionaryHint() { 672b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani return mShowingAddToDictionary; 673b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani } 674b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani 67566a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani public void showAddToDictionaryHint(CharSequence word) { 676717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka mWordToSave.setText(word); 67766a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani mShowingAddToDictionary = true; 67874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mCandidatesStrip.setVisibility(GONE); 67974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mTouchToSave.setVisibility(VISIBLE); 68066a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani } 68166a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani 6826558253160e2039c87f424bd814f402ecd31de3bKen Wakasa public boolean dismissAddToDictionaryHint() { 6836558253160e2039c87f424bd814f402ecd31de3bKen Wakasa if (!mShowingAddToDictionary) return false; 6846558253160e2039c87f424bd814f402ecd31de3bKen Wakasa clear(); 6856558253160e2039c87f424bd814f402ecd31de3bKen Wakasa return true; 6866558253160e2039c87f424bd814f402ecd31de3bKen Wakasa } 6876558253160e2039c87f424bd814f402ecd31de3bKen Wakasa 6887e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka public SuggestedWords getSuggestions() { 689979f8690967ff5409fe18f5085858ccdb8e0ccf1satok return mSuggestions; 690979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 691979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 692923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public void clear() { 69366a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani mShowingAddToDictionary = false; 69455b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka mShowingAutoCorrectionInverted = false; 69574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mTouchToSave.setVisibility(GONE); 69674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mCandidatesStrip.setVisibility(VISIBLE); 69774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mCandidatesStrip.removeAllViews(); 69886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka mCandidatesPane.removeAllViews(); 699923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 700923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 7016ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani private void hidePreview() { 702179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaoka mPreviewPopup.dismiss(); 7036ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani } 704e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka 705e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka private void showPreview(int index, CharSequence word) { 706e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka if (TextUtils.isEmpty(word)) 707e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka return; 708e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka 709e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka final TextView previewText = mPreviewText; 7101e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka previewText.setTextColor(mColorTypedWord); 711e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka previewText.setText(word); 712e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka previewText.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), 713e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); 714f20eb55d4f8063f89c6c0abb3af3029fe23cb845Tadashi G. Takaoka View v = mWords.get(index); 715e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka final int[] offsetInWindow = new int[2]; 716e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka v.getLocationInWindow(offsetInWindow); 717e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka final int posX = offsetInWindow[0]; 718e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka final int posY = offsetInWindow[1] - previewText.getMeasuredHeight(); 719e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka final PopupWindow previewPopup = mPreviewPopup; 720e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka if (previewPopup.isShowing()) { 721e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka previewPopup.update(posX, posY, previewPopup.getWidth(), previewPopup.getHeight()); 722e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka } else { 723e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka previewPopup.showAtLocation(this, Gravity.NO_GRAVITY, posX, posY); 724923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 725e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka previewText.setVisibility(VISIBLE); 72655b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka mHandler.postHidePreview(); 727923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 728fcba53ef7c874a4685c12c01404c91b779cae1e8Tadashi G. Takaoka 729e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka private void addToDictionary(CharSequence word) { 730c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka if (mListener.addWordToDictionary(word.toString())) { 731e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka showPreview(0, getContext().getString(R.string.added_word, word)); 732e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka } 733e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka } 734e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka 735e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka @Override 736e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka public boolean onLongClick(View view) { 73786e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka final Object tag = view.getTag(); 73886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka if (!(tag instanceof Integer)) 73986e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka return true; 74086e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka final int index = (Integer) tag; 74137deb112c727dfed5e94d054cf5f00f5d60c8120Tadashi G. Takaoka if (index >= mSuggestions.size()) 74237deb112c727dfed5e94d054cf5f00f5d60c8120Tadashi G. Takaoka return true; 74386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka 74437deb112c727dfed5e94d054cf5f00f5d60c8120Tadashi G. Takaoka final CharSequence word = mSuggestions.getWord(index); 745e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka if (word.length() < 2) 746e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka return false; 747e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka addToDictionary(word); 748e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka return true; 749e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka } 750e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka 751e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka @Override 752e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka public void onClick(View view) { 753717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka if (view == mWordToSave) { 754717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka addToDictionary(((TextView)view).getText()); 755717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka clear(); 756717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka return; 757717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka } 758717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka 75986e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka final Object tag = view.getTag(); 76086e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka if (!(tag instanceof Integer)) 76186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka return; 76286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka final int index = (Integer) tag; 76337deb112c727dfed5e94d054cf5f00f5d60c8120Tadashi G. Takaoka if (index >= mSuggestions.size()) 76437deb112c727dfed5e94d054cf5f00f5d60c8120Tadashi G. Takaoka return; 76586e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka 76637deb112c727dfed5e94d054cf5f00f5d60c8120Tadashi G. Takaoka final CharSequence word = mSuggestions.getWord(index); 767717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka mListener.pickSuggestionManually(index, word); 76886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka // Because some punctuation letters are not treated as word separator depending on locale, 76986e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka // {@link #setSuggestions} might not be called and candidates pane left opened. 77086e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka closeCandidatesPane(); 771923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 77282411d47ba7e8133ed2390c6920945e139a738cesatok 7736ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani @Override 7746ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani public void onDetachedFromWindow() { 7756ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani super.onDetachedFromWindow(); 77655b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka mHandler.cancelAllMessages(); 7776ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani hidePreview(); 7786ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani } 779923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project} 780