SuggestionStripView.java revision b47319867ef3834a222865b8cb6abe62962e70f7
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; 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; 4108a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaokaimport android.widget.ImageView; 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 6082411d47ba7e8133ed2390c6920945e139a738cesatok private static final CharacterStyle UNDERLINE_SPAN = new UnderlineSpan(); 6186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka // The maximum number of suggestions available. See {@link Suggest#mPrefMaxSuggestions}. 6286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka private static final int MAX_SUGGESTIONS = 18; 63b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka private static final int MATCH_PARENT = MeasureSpec.makeMeasureSpec( 64b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka -1, MeasureSpec.UNSPECIFIED); 65923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 668553b5ec315660ab53dd9234e64e1e39ea09ec0fJean Chalard private static final boolean DBG = LatinImeLogger.sDBG; 676f7218627eda110a8454053f8ecb7b80edfdc8cesatok 68717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka private final View mCandidatesStrip; 6986e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka private static final int NUM_CANDIDATES_IN_STRIP = 3; 7008a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka private final ImageView mExpandCandidatesPane; 7108a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka private final ImageView mCloseCandidatesPane; 7286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka private ViewGroup mCandidatesPane; 7386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka private ViewGroup mCandidatesPaneContainer; 7486e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka private View mKeyboardView; 751e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka private final ArrayList<TextView> mWords = new ArrayList<TextView>(); 762442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka private final ArrayList<TextView> mInfos = new ArrayList<TextView>(); 77ddb61ea461b920d87be4ad78c8a36eec1013b965Tadashi G. Takaoka private final ArrayList<View> mDividers = new ArrayList<View>(); 7886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka private final int mCandidateStripHeight; 7982411d47ba7e8133ed2390c6920945e139a738cesatok private final CharacterStyle mInvertedForegroundColorSpan; 8082411d47ba7e8133ed2390c6920945e139a738cesatok private final CharacterStyle mInvertedBackgroundColorSpan; 8108a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka private final int mAutoCorrectHighlight; 8208a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka private static final int AUTO_CORRECT_BOLD = 0x01; 8308a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka private static final int AUTO_CORRECT_UNDERLINE = 0x02; 8408a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka private static final int AUTO_CORRECT_INVERT = 0x04; 851e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka private final int mColorTypedWord; 861e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka private final int mColorAutoCorrect; 871e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka private final int mColorSuggestedCandidate; 8882411d47ba7e8133ed2390c6920945e139a738cesatok private final PopupWindow mPreviewPopup; 8982411d47ba7e8133ed2390c6920945e139a738cesatok private final TextView mPreviewText; 9066a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani 91717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka private final View mTouchToSave; 92717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka private final TextView mWordToSave; 93717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka 94c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka private Listener mListener; 957e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka private SuggestedWords mSuggestions = SuggestedWords.EMPTY; 9655b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka private boolean mShowingAutoCorrectionInverted; 97e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka private boolean mShowingAddToDictionary; 986a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani 99b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka private static final float MIN_TEXT_XSCALE = 0.4f; 100b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka private static final String ELLIPSIS = "\u2026"; 101b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka 1024f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa private final UiHandler mHandler = new UiHandler(this); 10355b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 1044f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa private static class UiHandler extends StaticInnerHandlerWrapper<CandidateView> { 10555b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka private static final int MSG_HIDE_PREVIEW = 0; 10655b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka private static final int MSG_UPDATE_SUGGESTION = 1; 10755b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 10855b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka private static final long DELAY_HIDE_PREVIEW = 1000; 10955b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka private static final long DELAY_UPDATE_SUGGESTION = 300; 11055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 1114f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa public UiHandler(CandidateView outerInstance) { 1124f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa super(outerInstance); 1134f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa } 1144f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa 115e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka @Override 116e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka public void dispatchMessage(Message msg) { 1174f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa final CandidateView candidateView = getOuterInstance(); 118e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka switch (msg.what) { 119e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka case MSG_HIDE_PREVIEW: 1204f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa candidateView.hidePreview(); 121e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka break; 12255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka case MSG_UPDATE_SUGGESTION: 1234f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa candidateView.updateSuggestions(); 12455b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka break; 125e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka } 126e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka } 12755b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 12855b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka public void postHidePreview() { 12955b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka cancelHidePreview(); 13055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka sendMessageDelayed(obtainMessage(MSG_HIDE_PREVIEW), DELAY_HIDE_PREVIEW); 13155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka } 13255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 13355b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka public void cancelHidePreview() { 13455b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka removeMessages(MSG_HIDE_PREVIEW); 13555b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka } 13655b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 1379fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka public void postUpdateSuggestions() { 13855b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka cancelUpdateSuggestions(); 1399fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka sendMessageDelayed(obtainMessage(MSG_UPDATE_SUGGESTION), 14055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka DELAY_UPDATE_SUGGESTION); 14155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka } 14255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 14355b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka public void cancelUpdateSuggestions() { 14455b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka removeMessages(MSG_UPDATE_SUGGESTION); 14555b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka } 14655b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 14755b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka public void cancelAllMessages() { 14855b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka cancelHidePreview(); 14955b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka cancelUpdateSuggestions(); 15055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka } 151e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka } 152179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaoka 153923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 154923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Construct a CandidateView for showing suggested words for completion. 155923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * @param context 156923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * @param attrs 157923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 158923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public CandidateView(Context context, AttributeSet attrs) { 15908a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka this(context, attrs, R.attr.candidateViewStyle); 16008a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka } 16108a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka 16208a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka public CandidateView(Context context, AttributeSet attrs, int defStyle) { 163f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka // Note: Up to version 10 (Gingerbread) of the API, LinearLayout doesn't have 3-argument 164f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka // constructor. 165f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka // TODO: Call 3-argument constructor, super(context, attrs, defStyle), when we abandon 166f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka // backward compatibility with the version 10 or earlier of the API. 167f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka super(context, attrs); 168f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka if (defStyle != R.attr.candidateViewStyle) { 169f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka throw new IllegalArgumentException( 170f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka "can't accept defStyle other than R.attr.candidayeViewStyle: defStyle=" 171f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka + defStyle); 172f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka } 173f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka setBackgroundDrawable(LinearLayoutCompatUtils.getBackgroundDrawable( 174f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka context, attrs, defStyle, R.style.CandidateViewStyle)); 175923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 17666a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani Resources res = context.getResources(); 177e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka LayoutInflater inflater = LayoutInflater.from(context); 17886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka inflater.inflate(R.layout.candidates_strip, this); 17986e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka 18086e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka mPreviewPopup = new PopupWindow(context); 181e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka mPreviewText = (TextView) inflater.inflate(R.layout.candidate_preview, null); 182e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka mPreviewPopup.setWindowLayoutMode(ViewGroup.LayoutParams.WRAP_CONTENT, 183e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka ViewGroup.LayoutParams.WRAP_CONTENT); 184923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project mPreviewPopup.setContentView(mPreviewText); 185923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project mPreviewPopup.setBackgroundDrawable(null); 186923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 187717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka mCandidatesStrip = findViewById(R.id.candidates_strip); 18886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka mCandidateStripHeight = res.getDimensionPixelOffset(R.dimen.candidate_strip_height); 189e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka for (int i = 0; i < MAX_SUGGESTIONS; i++) { 1902442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka final TextView word, info; 19186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka switch (i) { 19286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka case 0: 1932442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka word = (TextView)findViewById(R.id.word_left); 1942442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka info = (TextView)findViewById(R.id.info_left); 19586e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka break; 19686e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka case 1: 1972442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka word = (TextView)findViewById(R.id.word_center); 1982442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka info = (TextView)findViewById(R.id.info_center); 19986e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka break; 20086e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka case 2: 2012442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka word = (TextView)findViewById(R.id.word_right); 2022442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka info = (TextView)findViewById(R.id.info_right); 20386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka break; 20486e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka default: 2052442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka word = (TextView)inflater.inflate(R.layout.candidate_word, null); 2062442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka info = (TextView)inflater.inflate(R.layout.candidate_info, null); 20786e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka break; 20886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka } 2092442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka word.setTag(i); 2102442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka word.setOnClickListener(this); 211e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka if (i == 0) 2122442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka word.setOnLongClickListener(this); 2132442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka mWords.add(word); 2142442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka mInfos.add(info); 215ddb61ea461b920d87be4ad78c8a36eec1013b965Tadashi G. Takaoka if (i > 0) { 216070760dc5abdb9a850a94c509eeb9f486515af59Tadashi G. Takaoka final View divider = inflater.inflate(R.layout.candidate_divider, null); 217b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka divider.measure(MATCH_PARENT, MATCH_PARENT); 218ddb61ea461b920d87be4ad78c8a36eec1013b965Tadashi G. Takaoka mDividers.add(divider); 219ddb61ea461b920d87be4ad78c8a36eec1013b965Tadashi G. Takaoka } 220c9716b28ce438e06b5cacc07fc002944bcbe24a0Tadashi G. Takaoka } 221179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaoka 222717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka mTouchToSave = findViewById(R.id.touch_to_save); 223717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka mWordToSave = (TextView)findViewById(R.id.word_to_save); 224717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka mWordToSave.setOnClickListener(this); 225717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka 22608a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka final TypedArray a = context.obtainStyledAttributes( 22708a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka attrs, R.styleable.CandidateView, defStyle, R.style.CandidateViewStyle); 22808a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka mAutoCorrectHighlight = a.getInt(R.styleable.CandidateView_autoCorrectHighlight, 0); 22908a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka mColorTypedWord = a.getColor(R.styleable.CandidateView_colorTypedWord, 0); 23008a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka mColorAutoCorrect = a.getColor(R.styleable.CandidateView_colorAutoCorrect, 0); 23108a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka mColorSuggestedCandidate = a.getColor(R.styleable.CandidateView_colorSuggested, 0); 23208a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka mInvertedForegroundColorSpan = new ForegroundColorSpan(mColorTypedWord ^ 0x00ffffff); 23308a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka mInvertedBackgroundColorSpan = new BackgroundColorSpan(mColorTypedWord); 23408a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka 23508a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka mExpandCandidatesPane = (ImageView)findViewById(R.id.expand_candidates_pane); 23608a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka mExpandCandidatesPane.setImageDrawable( 23708a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka a.getDrawable(R.styleable.CandidateView_iconExpandPane)); 23886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka mExpandCandidatesPane.setOnClickListener(new OnClickListener() { 23986e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka @Override 24086e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka public void onClick(View view) { 24186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka expandCandidatesPane(); 24286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka } 24386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka }); 24408a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka mCloseCandidatesPane = (ImageView)findViewById(R.id.close_candidates_pane); 24508a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka mCloseCandidatesPane.setImageDrawable( 24608a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka a.getDrawable(R.styleable.CandidateView_iconClosePane)); 24786e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka mCloseCandidatesPane.setOnClickListener(new OnClickListener() { 24886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka @Override 24986e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka public void onClick(View view) { 25086e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka closeCandidatesPane(); 25186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka } 25286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka }); 25308a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka 25408a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka a.recycle(); 255923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 256c9716b28ce438e06b5cacc07fc002944bcbe24a0Tadashi G. Takaoka 257923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 258c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka * A connection back to the input method. 259923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * @param listener 260923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 26186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka public void setListener(Listener listener, View inputView) { 262c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka mListener = listener; 26386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka mKeyboardView = inputView.findViewById(R.id.keyboard_view); 264a7eed902f1b0d6871d416412b3c6f91163fa2578Tadashi G. Takaoka mCandidatesPane = FrameLayoutCompatUtils.getPlacer( 265a7eed902f1b0d6871d416412b3c6f91163fa2578Tadashi G. Takaoka (ViewGroup)inputView.findViewById(R.id.candidates_pane)); 26686e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka mCandidatesPane.setOnClickListener(this); 26786e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka mCandidatesPaneContainer = (ViewGroup)inputView.findViewById( 26886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka R.id.candidates_pane_container); 269923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 270923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 2717e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka public void setSuggestions(SuggestedWords suggestions) { 2729fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka if (suggestions == null) 273a15e45ef45931ba46678b39c159518d8aa2d4d65Tadashi G. Takaoka return; 2749fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka mSuggestions = suggestions; 27555b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka if (mShowingAutoCorrectionInverted) { 2769fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka mHandler.postUpdateSuggestions(); 27755b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka } else { 2789fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka updateSuggestions(); 27955b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka } 28055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka } 28155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 282b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka private CharSequence getStyledCandidateWord(CharSequence word, TextView v, 283b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka boolean isAutoCorrect) { 284b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka v.setTypeface(Typeface.DEFAULT); 2851e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka if (!isAutoCorrect) 2861e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka return word; 2871e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka final Spannable spannedWord = new SpannableString(word); 28808a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka if ((mAutoCorrectHighlight & AUTO_CORRECT_BOLD) != 0) 289b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka v.setTypeface(Typeface.DEFAULT_BOLD); 29008a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka if ((mAutoCorrectHighlight & AUTO_CORRECT_UNDERLINE) != 0) 29108a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka spannedWord.setSpan(UNDERLINE_SPAN, 0, word.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE); 2921e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka return spannedWord; 2931e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka } 2941e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka 2951e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka private int getCandidateTextColor(boolean isAutoCorrect, boolean isSuggestedCandidate, 2961e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka SuggestedWordInfo info) { 2971e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka final int color; 29808a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka if (isAutoCorrect) { 2991e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka color = mColorAutoCorrect; 30008a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka } else if (isSuggestedCandidate) { 3011e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka color = mColorSuggestedCandidate; 3021e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka } else { 3031e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka color = mColorTypedWord; 3041e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka } 3051e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka if (info != null && info.isPreviousSuggestedWord()) { 3061e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka final int newAlpha = (int)(Color.alpha(color) * 0.5f); 3071e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka return Color.argb(newAlpha, Color.red(color), Color.green(color), Color.blue(color)); 3081e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka } else { 3091e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka return color; 3101e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka } 3111e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka } 3121e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka 3139fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka private void updateSuggestions() { 3149fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka final SuggestedWords suggestions = mSuggestions; 3151e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka final List<SuggestedWordInfo> suggestedWordInfoList = suggestions.mSuggestedWordInfoList; 3161e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka 317e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka clear(); 31886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka final int paneWidth = getWidth(); 31986e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka final int dividerWidth = mDividers.get(0).getMeasuredWidth(); 3202442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka final int dividerHeight = mDividers.get(0).getMeasuredHeight(); 32186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka int x = 0; 32286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka int y = 0; 32386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka int fromIndex = NUM_CANDIDATES_IN_STRIP; 324ec5ae3a1b6ce6d6c87406def849995ec63816c55Ken Wakasa final int count = Math.min(mWords.size(), suggestions.size()); 32586e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka closeCandidatesPane(); 326b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka mExpandCandidatesPane.setVisibility(count > NUM_CANDIDATES_IN_STRIP ? VISIBLE : GONE); 327923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project for (int i = 0; i < count; i++) { 3282442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka final CharSequence suggestion = suggestions.getWord(i); 3292442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka if (suggestion == null) continue; 3301e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka 3312442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka final SuggestedWordInfo suggestionInfo = (suggestedWordInfoList != null) 3321e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka ? suggestedWordInfoList.get(i) : null; 3331e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka final boolean isAutoCorrect = suggestions.mHasMinimalSuggestion 33482411d47ba7e8133ed2390c6920945e139a738cesatok && ((i == 1 && !suggestions.mTypedWordValid) 3351e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka || (i == 0 && suggestions.mTypedWordValid)); 3361e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka // HACK: even if i == 0, we use mColorOther when this suggestion's length is 1 3371e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka // and there are multiple suggestions, such as the default punctuation list. 3381e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka // TODO: Need to revisit this logic with bigram suggestions 3391e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka final boolean isSuggestedCandidate = (i != 0); 3402442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka final boolean isPunctuationSuggestions = (suggestion.length() == 1 && count > 1); 3411e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka 3422442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka final TextView word = mWords.get(i); 34386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka // TODO: Reorder candidates in strip as appropriate. The center candidate should hold 34486e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka // the word when space is typed (valid typed word or auto corrected word). 3452442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka word.setTextColor(getCandidateTextColor(isAutoCorrect, 3462442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka isSuggestedCandidate || isPunctuationSuggestions, suggestionInfo)); 347b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka final CharSequence text = getStyledCandidateWord(suggestion, word, isAutoCorrect); 348b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka if (i < NUM_CANDIDATES_IN_STRIP) { 349b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka final View parent = (View)word.getParent(); 350b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka final int width = parent.getWidth() - word.getPaddingLeft() 351b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka - word.getPaddingRight(); 352b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka setTextWithAutoScaleAndEllipsis(text, width, word); 353b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka } else { 354b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka setTextWithAutoScaleAndEllipsis(text, paneWidth, word); 355b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka } 3562442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka 3572442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka final TextView info; 3582442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka if (DBG && suggestionInfo != null 3592442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka && !TextUtils.isEmpty(suggestionInfo.getDebugString())) { 3602442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka info = mInfos.get(i); 3612442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka info.setText(suggestionInfo.getDebugString()); 3622442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka info.setVisibility(View.VISIBLE); 3632442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka } else { 3642442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka info = null; 3652442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka } 3662442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka 3672442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka if (i < NUM_CANDIDATES_IN_STRIP) { 3682442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka if (info != null) { 369b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka word.measure(MATCH_PARENT, MATCH_PARENT); 370b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka info.measure(MATCH_PARENT, MATCH_PARENT); 371b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka final int width = word.getMeasuredWidth(); 3722442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka final int infoWidth = info.getMeasuredWidth(); 3732442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka FrameLayoutCompatUtils.placeViewAt( 3747fb04fe007a6d0489168e9c87771db554c873464Tadashi G. Takaoka info, width - infoWidth, 0, infoWidth, info.getMeasuredHeight()); 3752442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka } 3762442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka } else { 377b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka word.measure(MATCH_PARENT, MATCH_PARENT); 378b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka final int width = word.getMeasuredWidth(); 379b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka final int height = word.getMeasuredHeight(); 38086e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka // TODO: Handle overflow case. 38186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka if (dividerWidth + x + width >= paneWidth) { 38286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka centeringCandidates(fromIndex, i - 1, x, paneWidth); 38386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka x = 0; 38486e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka y += mCandidateStripHeight; 38586e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka fromIndex = i; 38686e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka } 38786e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka if (x != 0) { 38886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka final View divider = mDividers.get(i - NUM_CANDIDATES_IN_STRIP); 3892442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka mCandidatesPane.addView(divider); 3902442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka FrameLayoutCompatUtils.placeViewAt( 3912442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka divider, x, y + (mCandidateStripHeight - dividerHeight) / 2, 3922442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka dividerWidth, dividerHeight); 39386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka x += dividerWidth; 39486e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka } 3952442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka mCandidatesPane.addView(word); 3962442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka FrameLayoutCompatUtils.placeViewAt( 3972442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka word, x, y + (mCandidateStripHeight - height) / 2, width, height); 3982442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka if (info != null) { 3992442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka mCandidatesPane.addView(info); 400b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka info.measure(MATCH_PARENT, MATCH_PARENT); 4012442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka final int infoWidth = info.getMeasuredWidth(); 4022442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka FrameLayoutCompatUtils.placeViewAt( 4032442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka info, x + width - infoWidth, y, infoWidth, info.getMeasuredHeight()); 4042442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka } 40586e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka x += width; 4067e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka } 407923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 40886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka if (x != 0) { 40986e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka // Centering last candidates row. 41086e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka centeringCandidates(fromIndex, count - 1, x, paneWidth); 41186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka } 41286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka } 41386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka 41486e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka private void centeringCandidates(int from, int to, int width, int paneWidth) { 41586e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka final ViewGroup pane = mCandidatesPane; 41686e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka final int fromIndex = pane.indexOfChild(mWords.get(from)); 4172442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka final int toIndex; 4182442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka if (mInfos.get(to).getParent() != null) { 4192442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka toIndex = pane.indexOfChild(mInfos.get(to)); 4202442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka } else { 4212442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka toIndex = pane.indexOfChild(mWords.get(to)); 4222442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka } 42386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka final int offset = (paneWidth - width) / 2; 42486e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka for (int index = fromIndex; index <= toIndex; index++) { 42586e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka offsetMargin(pane.getChildAt(index), offset, 0); 42686e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka } 42786e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka } 42886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka 42986e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka private static void offsetMargin(View v, int dx, int dy) { 430862e05a8f0aa03ddc4582d5bf68a3201f348cf1dTadashi G. Takaoka if (v == null) 431862e05a8f0aa03ddc4582d5bf68a3201f348cf1dTadashi G. Takaoka return; 4322442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka final ViewGroup.LayoutParams lp = v.getLayoutParams(); 43386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka if (lp instanceof ViewGroup.MarginLayoutParams) { 4342442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka final ViewGroup.MarginLayoutParams mlp = (ViewGroup.MarginLayoutParams)lp; 43586e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka mlp.setMargins(mlp.leftMargin + dx, mlp.topMargin + dy, 0, 0); 43686e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka } 43786e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka } 43886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka 439b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka private static void setTextWithAutoScaleAndEllipsis(CharSequence text, int w, TextView v) { 440b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka // To prevent partially rendered character at the end of text, subtract few extra pixels 441b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka // from the width. 442b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka final int width = w - 4; 443b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka 444b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka final TextPaint paint = v.getPaint(); 445b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka final int textWidth = getTextWidth(text, paint, 1.0f); 446b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka if (textWidth < width || textWidth == 0 || width <= 0) { 447b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka v.setTextScaleX(1.0f); 448b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka v.setText(text); 449b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka return; 450b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka } 451b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka 452b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka final float scaleX = Math.min((float)width / textWidth, 1.0f); 453b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka if (scaleX >= MIN_TEXT_XSCALE) { 454b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka v.setTextScaleX(scaleX); 455b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka v.setText(text); 456b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka return; 457b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka } 458b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka 459b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka final int truncatedWidth = width - getTextWidth(ELLIPSIS, paint, MIN_TEXT_XSCALE); 460b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka final CharSequence ellipsized = getTextEllipsizedAtStart(text, paint, truncatedWidth); 461b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka v.setTextScaleX(MIN_TEXT_XSCALE); 462b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka v.setText(ELLIPSIS); 463b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka v.append(ellipsized); 464b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka } 465b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka 466b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka private static int getTextWidth(CharSequence text, TextPaint paint, float scaleX) { 467b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka if (TextUtils.isEmpty(text)) return 0; 468b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka final int len = text.length(); 469b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka final float[] widths = new float[len]; 470b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka paint.setTextScaleX(scaleX); 471b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka final int count = paint.getTextWidths(text, 0, len, widths); 472b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka float width = 0; 473b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka for (int i = 0; i < count; i++) { 474b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka width += widths[i]; 475b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka } 476b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka return (int)Math.round(width + 0.5); 477b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka } 478b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka 479b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka private static CharSequence getTextEllipsizedAtStart(CharSequence text, TextPaint paint, 480b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka int maxWidth) { 481b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka final int len = text.length(); 482b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka final float[] widths = new float[len]; 483b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka final int count = paint.getTextWidths(text, 0, len, widths); 484b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka float width = 0; 485b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka for (int i = count - 1; i >= 0; i--) { 486b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka width += widths[i]; 487b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka if (width > maxWidth) 488b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka return text.subSequence(i + 1, len); 489b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka } 490b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka return text; 491b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka } 492b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka 49386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka private void expandCandidatesPane() { 49486e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka mExpandCandidatesPane.setVisibility(View.GONE); 49586e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka mCloseCandidatesPane.setVisibility(View.VISIBLE); 49686e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka mCandidatesPaneContainer.setMinimumHeight(mKeyboardView.getMeasuredHeight()); 49786e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka mCandidatesPaneContainer.setVisibility(View.VISIBLE); 49886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka mKeyboardView.setVisibility(View.GONE); 49986e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka } 500e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka 50186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka private void closeCandidatesPane() { 50286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka mExpandCandidatesPane.setVisibility(View.VISIBLE); 50386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka mCloseCandidatesPane.setVisibility(View.GONE); 50486e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka mCandidatesPaneContainer.setVisibility(View.GONE); 50586e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka mKeyboardView.setVisibility(View.VISIBLE); 506923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 507923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 50855b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka public void onAutoCorrectionInverted(CharSequence autoCorrectedWord) { 50908a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka if ((mAutoCorrectHighlight & AUTO_CORRECT_INVERT) == 0) 51055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka return; 5111e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka final TextView tv = mWords.get(1); 51255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka final Spannable word = new SpannableString(autoCorrectedWord); 51355b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka final int wordLength = word.length(); 5148553b5ec315660ab53dd9234e64e1e39ea09ec0fJean Chalard word.setSpan(mInvertedBackgroundColorSpan, 0, wordLength, 5158553b5ec315660ab53dd9234e64e1e39ea09ec0fJean Chalard Spanned.SPAN_INCLUSIVE_EXCLUSIVE); 5168553b5ec315660ab53dd9234e64e1e39ea09ec0fJean Chalard word.setSpan(mInvertedForegroundColorSpan, 0, wordLength, 5178553b5ec315660ab53dd9234e64e1e39ea09ec0fJean Chalard Spanned.SPAN_INCLUSIVE_EXCLUSIVE); 51855b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka tv.setText(word); 51955b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka mShowingAutoCorrectionInverted = true; 52055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka } 52155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 522b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani public boolean isShowingAddToDictionaryHint() { 523b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani return mShowingAddToDictionary; 524b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani } 525b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani 52666a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani public void showAddToDictionaryHint(CharSequence word) { 527717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka mWordToSave.setText(word); 52866a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani mShowingAddToDictionary = true; 529717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka mCandidatesStrip.setVisibility(View.GONE); 530717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka mTouchToSave.setVisibility(View.VISIBLE); 53166a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani } 53266a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani 5336558253160e2039c87f424bd814f402ecd31de3bKen Wakasa public boolean dismissAddToDictionaryHint() { 5346558253160e2039c87f424bd814f402ecd31de3bKen Wakasa if (!mShowingAddToDictionary) return false; 5356558253160e2039c87f424bd814f402ecd31de3bKen Wakasa clear(); 5366558253160e2039c87f424bd814f402ecd31de3bKen Wakasa return true; 5376558253160e2039c87f424bd814f402ecd31de3bKen Wakasa } 5386558253160e2039c87f424bd814f402ecd31de3bKen Wakasa 5397e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka public SuggestedWords getSuggestions() { 540979f8690967ff5409fe18f5085858ccdb8e0ccf1satok return mSuggestions; 541979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 542979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 543923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public void clear() { 54466a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani mShowingAddToDictionary = false; 54555b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka mShowingAutoCorrectionInverted = false; 5462442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka for (int i = 0; i < NUM_CANDIDATES_IN_STRIP; i++) { 54786e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka mWords.get(i).setText(null); 5482442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka mInfos.get(i).setVisibility(View.GONE); 5492442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka } 550717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka mTouchToSave.setVisibility(View.GONE); 551717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka mCandidatesStrip.setVisibility(View.VISIBLE); 55286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka mCandidatesPane.removeAllViews(); 553923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 554923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 5556ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani private void hidePreview() { 556179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaoka mPreviewPopup.dismiss(); 5576ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani } 558e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka 559e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka private void showPreview(int index, CharSequence word) { 560e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka if (TextUtils.isEmpty(word)) 561e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka return; 562e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka 563e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka final TextView previewText = mPreviewText; 5641e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka previewText.setTextColor(mColorTypedWord); 565e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka previewText.setText(word); 566e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka previewText.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), 567e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); 568f20eb55d4f8063f89c6c0abb3af3029fe23cb845Tadashi G. Takaoka View v = mWords.get(index); 569e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka final int[] offsetInWindow = new int[2]; 570e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka v.getLocationInWindow(offsetInWindow); 571e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka final int posX = offsetInWindow[0]; 572e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka final int posY = offsetInWindow[1] - previewText.getMeasuredHeight(); 573e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka final PopupWindow previewPopup = mPreviewPopup; 574e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka if (previewPopup.isShowing()) { 575e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka previewPopup.update(posX, posY, previewPopup.getWidth(), previewPopup.getHeight()); 576e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka } else { 577e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka previewPopup.showAtLocation(this, Gravity.NO_GRAVITY, posX, posY); 578923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 579e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka previewText.setVisibility(VISIBLE); 58055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka mHandler.postHidePreview(); 581923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 582fcba53ef7c874a4685c12c01404c91b779cae1e8Tadashi G. Takaoka 583e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka private void addToDictionary(CharSequence word) { 584c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka if (mListener.addWordToDictionary(word.toString())) { 585e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka showPreview(0, getContext().getString(R.string.added_word, word)); 586e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka } 587e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka } 588e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka 589e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka @Override 590e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka public boolean onLongClick(View view) { 59186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka final Object tag = view.getTag(); 59286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka if (!(tag instanceof Integer)) 59386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka return true; 59486e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka final int index = (Integer) tag; 59537deb112c727dfed5e94d054cf5f00f5d60c8120Tadashi G. Takaoka if (index >= mSuggestions.size()) 59637deb112c727dfed5e94d054cf5f00f5d60c8120Tadashi G. Takaoka return true; 59786e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka 59837deb112c727dfed5e94d054cf5f00f5d60c8120Tadashi G. Takaoka final CharSequence word = mSuggestions.getWord(index); 599e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka if (word.length() < 2) 600e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka return false; 601e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka addToDictionary(word); 602e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka return true; 603e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka } 604e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka 605e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka @Override 606e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka public void onClick(View view) { 607717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka if (view == mWordToSave) { 608717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka addToDictionary(((TextView)view).getText()); 609717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka clear(); 610717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka return; 611717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka } 612717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka 61386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka final Object tag = view.getTag(); 61486e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka if (!(tag instanceof Integer)) 61586e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka return; 61686e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka final int index = (Integer) tag; 61737deb112c727dfed5e94d054cf5f00f5d60c8120Tadashi G. Takaoka if (index >= mSuggestions.size()) 61837deb112c727dfed5e94d054cf5f00f5d60c8120Tadashi G. Takaoka return; 61986e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka 62037deb112c727dfed5e94d054cf5f00f5d60c8120Tadashi G. Takaoka final CharSequence word = mSuggestions.getWord(index); 621717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka mListener.pickSuggestionManually(index, word); 62286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka // Because some punctuation letters are not treated as word separator depending on locale, 62386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka // {@link #setSuggestions} might not be called and candidates pane left opened. 62486e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka closeCandidatesPane(); 625923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 62682411d47ba7e8133ed2390c6920945e139a738cesatok 6276ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani @Override 6286ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani public void onDetachedFromWindow() { 6296ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani super.onDetachedFromWindow(); 63055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka mHandler.cancelAllMessages(); 6316ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani hidePreview(); 6326ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani } 633923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project} 634