SuggestionStripView.java revision ae5c736e37973e26b201d45ff6c139862a6e05cf
1923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project/*
2e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka * Copyright (C) 2010 The Android Open Source Project
3e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka *
4923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * use this file except in compliance with the License. You may obtain a copy of
6923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * the License at
7e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka *
8923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0
9e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka *
10923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
11923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * License for the specific language governing permissions and limitations under
14923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * the License.
15923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */
16923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
17923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectpackage com.android.inputmethod.latin;
18923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
19923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.Context;
2066a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasaniimport android.content.res.Resources;
2108a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaokaimport android.content.res.TypedArray;
226f7218627eda110a8454053f8ecb7b80edfdc8cesatokimport android.graphics.Color;
23923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.graphics.Typeface;
24e583371b13ebd9aa336d0883e8c174ae4918c758Tadashi G. Takaokaimport android.graphics.drawable.Drawable;
25e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaokaimport android.os.Message;
26522d5c16d20657e7d26009fe9c067404e16a6c2aTadashi G. Takaokaimport android.text.Spannable;
27522d5c16d20657e7d26009fe9c067404e16a6c2aTadashi G. Takaokaimport android.text.SpannableString;
28e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaokaimport android.text.Spanned;
29b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaokaimport android.text.TextPaint;
30e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaokaimport android.text.TextUtils;
3155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaokaimport android.text.style.BackgroundColorSpan;
32522d5c16d20657e7d26009fe9c067404e16a6c2aTadashi G. Takaokaimport android.text.style.CharacterStyle;
3355b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaokaimport android.text.style.ForegroundColorSpan;
3474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaokaimport android.text.style.StyleSpan;
35522d5c16d20657e7d26009fe9c067404e16a6c2aTadashi G. Takaokaimport android.text.style.UnderlineSpan;
36923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.util.AttributeSet;
37923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.Gravity;
38923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.LayoutInflater;
39923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.View;
40e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaokaimport android.view.View.OnClickListener;
41ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaokaimport android.view.View.OnLongClickListener;
42e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaokaimport android.view.ViewGroup;
43e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaokaimport android.widget.LinearLayout;
44923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.widget.PopupWindow;
45923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.widget.TextView;
46923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
47a7eed902f1b0d6871d416412b3c6f91163fa2578Tadashi G. Takaokaimport com.android.inputmethod.compat.FrameLayoutCompatUtils;
48f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaokaimport com.android.inputmethod.compat.LinearLayoutCompatUtils;
49ddb61ea461b920d87be4ad78c8a36eec1013b965Tadashi G. Takaokaimport com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
50ddb61ea461b920d87be4ad78c8a36eec1013b965Tadashi G. Takaoka
51179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaokaimport java.util.ArrayList;
526f7218627eda110a8454053f8ecb7b80edfdc8cesatokimport java.util.List;
53179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaoka
54ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaokapublic class CandidateView extends LinearLayout implements OnClickListener, OnLongClickListener {
55c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka    public interface Listener {
56c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka        public boolean addWordToDictionary(String word);
57c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka        public void pickSuggestionManually(int index, CharSequence word);
58c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka    }
59c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka
6086e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka    // The maximum number of suggestions available. See {@link Suggest#mPrefMaxSuggestions}.
6186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka    private static final int MAX_SUGGESTIONS = 18;
6274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka    private static final int WRAP_CONTENT = ViewGroup.LayoutParams.WRAP_CONTENT;
633118277dd47492089761c0ed1097abaeb376395cTadashi G. Takaoka    private static final int MATCH_PARENT = ViewGroup.LayoutParams.MATCH_PARENT;
64923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
658553b5ec315660ab53dd9234e64e1e39ea09ec0fJean Chalard    private static final boolean DBG = LatinImeLogger.sDBG;
666f7218627eda110a8454053f8ecb7b80edfdc8cesatok
6774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka    private final ViewGroup mCandidatesStrip;
6886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka    private ViewGroup mCandidatesPane;
6986e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka    private ViewGroup mCandidatesPaneContainer;
7086e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka    private View mKeyboardView;
7174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
721e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka    private final ArrayList<TextView> mWords = new ArrayList<TextView>();
732442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka    private final ArrayList<TextView> mInfos = new ArrayList<TextView>();
74ddb61ea461b920d87be4ad78c8a36eec1013b965Tadashi G. Takaoka    private final ArrayList<View> mDividers = new ArrayList<View>();
7574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
7682411d47ba7e8133ed2390c6920945e139a738cesatok    private final PopupWindow mPreviewPopup;
7782411d47ba7e8133ed2390c6920945e139a738cesatok    private final TextView mPreviewText;
7866a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani
79717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka    private final View mTouchToSave;
80717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka    private final TextView mWordToSave;
81717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka
82c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka    private Listener mListener;
837e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka    private SuggestedWords mSuggestions = SuggestedWords.EMPTY;
8455b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka    private boolean mShowingAutoCorrectionInverted;
85e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka    private boolean mShowingAddToDictionary;
866a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani
87d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka    private final SuggestionsStripParams mStripParams;
88d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka    private final SuggestionsPaneParams mPaneParams;
89ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka    private static final float MIN_TEXT_XSCALE = 0.70f;
90b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka
914f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa    private final UiHandler mHandler = new UiHandler(this);
9255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka
934f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa    private static class UiHandler extends StaticInnerHandlerWrapper<CandidateView> {
9455b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        private static final int MSG_HIDE_PREVIEW = 0;
9555b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        private static final int MSG_UPDATE_SUGGESTION = 1;
9655b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka
9755b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        private static final long DELAY_HIDE_PREVIEW = 1000;
9855b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        private static final long DELAY_UPDATE_SUGGESTION = 300;
9955b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka
1004f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa        public UiHandler(CandidateView outerInstance) {
1014f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa            super(outerInstance);
1024f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa        }
1034f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa
104e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        @Override
105e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        public void dispatchMessage(Message msg) {
1064f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa            final CandidateView candidateView = getOuterInstance();
107e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka            switch (msg.what) {
108e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka            case MSG_HIDE_PREVIEW:
1094f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa                candidateView.hidePreview();
110e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka                break;
11155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            case MSG_UPDATE_SUGGESTION:
1124f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa                candidateView.updateSuggestions();
11355b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka                break;
114e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka            }
115e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        }
11655b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka
11755b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        public void postHidePreview() {
11855b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            cancelHidePreview();
11955b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            sendMessageDelayed(obtainMessage(MSG_HIDE_PREVIEW), DELAY_HIDE_PREVIEW);
12055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        }
12155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka
12255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        public void cancelHidePreview() {
12355b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            removeMessages(MSG_HIDE_PREVIEW);
12455b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        }
12555b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka
1269fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        public void postUpdateSuggestions() {
12755b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            cancelUpdateSuggestions();
1289fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            sendMessageDelayed(obtainMessage(MSG_UPDATE_SUGGESTION),
12955b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka                    DELAY_UPDATE_SUGGESTION);
13055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        }
13155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka
13255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        public void cancelUpdateSuggestions() {
13355b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            removeMessages(MSG_UPDATE_SUGGESTION);
13455b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        }
13555b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka
13655b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        public void cancelAllMessages() {
13755b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            cancelHidePreview();
13855b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            cancelUpdateSuggestions();
13955b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        }
140e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka    }
141179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaoka
142d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka    private static class CandidateViewParams {
14374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        public final int mPadding;
14474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        public final int mDividerWidth;
14574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        public final int mDividerHeight;
14616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka        public final int mCandidateStripHeight;
14716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka
14816713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka        protected final List<TextView> mWords;
14916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka        protected final List<View> mDividers;
15016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka        protected final List<TextView> mInfos;
151d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka
15216713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka        protected CandidateViewParams(List<TextView> words, List<View> dividers,
153ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka                List<TextView> infos) {
15416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka            mWords = words;
15516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka            mDividers = dividers;
15616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka            mInfos = infos;
15716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka
15816713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka            final TextView word = words.get(0);
15916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka            final View divider = dividers.get(0);
160d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            mPadding = word.getCompoundPaddingLeft() + word.getCompoundPaddingRight();
161d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            divider.measure(WRAP_CONTENT, MATCH_PARENT);
162d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            mDividerWidth = divider.getMeasuredWidth();
163d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            mDividerHeight = divider.getMeasuredHeight();
16416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka
16516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka            final Resources res = word.getResources();
16616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka            mCandidateStripHeight = res.getDimensionPixelOffset(R.dimen.candidate_strip_height);
167d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        }
168d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka    }
169d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka
170d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka    private static class SuggestionsPaneParams extends CandidateViewParams {
17116713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka        public SuggestionsPaneParams(List<TextView> words, List<View> dividers,
172ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka                List<TextView> infos) {
173ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka            super(words, dividers, infos);
17416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka        }
17516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka
17616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka        public int layout(SuggestedWords suggestions, ViewGroup paneView, int from, int textColor,
17716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                int paneWidth) {
17816713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka            final int count = Math.min(mWords.size(), suggestions.size());
17916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka            View centeringFrom = null, lastView = null;
18016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka            int x = 0, y = 0;
18116713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka            for (int index = from; index < count; index++) {
18216713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                final int pos = index;
18316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                final TextView word = mWords.get(pos);
18416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                final View divider = mDividers.get(pos);
18516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                final TextPaint paint = word.getPaint();
18616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                word.setTextColor(textColor);
18716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                final CharSequence styled = suggestions.getWord(pos);
18816713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka
18916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                final TextView info;
19016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                if (DBG) {
19116713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    final CharSequence debugInfo = getDebugInfo(suggestions, index);
19216713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    if (debugInfo != null) {
19316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                        info = mInfos.get(index);
19416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                        info.setText(debugInfo);
19516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    } else {
19616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                        info = null;
19716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    }
19816713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                } else {
19916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    info = null;
20016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                }
20116713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka
20216713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                final CharSequence text;
20316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                final float scaleX;
20416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                paint.setTextScaleX(1.0f);
20516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                final int textWidth = getTextWidth(styled, paint);
20616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                int available = paneWidth - x - mPadding;
20716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                if (textWidth >= available) {
20816713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    // Needs new row, centering previous row.
20916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    centeringCandidates(paneView, centeringFrom, lastView, x, paneWidth);
21016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    x = 0;
21116713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    y += mCandidateStripHeight;
21216713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                }
21316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                if (x != 0) {
21416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    // Add divider if this isn't the left most suggestion in current row.
21516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    paneView.addView(divider);
21616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    FrameLayoutCompatUtils.placeViewAt(divider, x, y
21716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                            + (mCandidateStripHeight - mDividerHeight) / 2, mDividerWidth,
21816713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                            mDividerHeight);
21916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    x += mDividerWidth;
22016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                }
22116713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                available = paneWidth - x - mPadding;
22216713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                text = getEllipsizedText(styled, available, paint);
22316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                scaleX = paint.getTextScaleX();
22416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                word.setText(text);
22516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                word.setTextScaleX(scaleX);
22616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                paneView.addView(word);
22716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                lastView = word;
22816713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                if (x == 0)
22916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    centeringFrom = word;
23016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                word.measure(WRAP_CONTENT,
23116713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                        MeasureSpec.makeMeasureSpec(mCandidateStripHeight, MeasureSpec.EXACTLY));
23216713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                final int width = word.getMeasuredWidth();
23316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                final int height = word.getMeasuredHeight();
23416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                FrameLayoutCompatUtils.placeViewAt(word, x, y + (mCandidateStripHeight - height)
23516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                        / 2, width, height);
23616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                x += width;
23716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                if (info != null) {
23816713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    paneView.addView(info);
23916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    lastView = info;
24016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    info.measure(WRAP_CONTENT, WRAP_CONTENT);
24116713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    final int infoWidth = info.getMeasuredWidth();
24216713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    FrameLayoutCompatUtils.placeViewAt(info, x - infoWidth, y, infoWidth,
24316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                            info.getMeasuredHeight());
24416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                }
24516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka            }
24616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka            if (x != 0) {
24716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                // Centering last candidates row.
24816713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                centeringCandidates(paneView, centeringFrom, lastView, x, paneWidth);
24916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka            }
25016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka
25116713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka            return count - from;
252d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        }
253d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka    }
254d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka
255d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka    private static class SuggestionsStripParams extends CandidateViewParams {
256d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        private static final int DEFAULT_CANDIDATE_COUNT_IN_STRIP = 3;
25760a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka        private static final int DEFAULT_CENTER_CANDIDATE_PERCENTILE = 40;
258d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        private static final int PUNCTUATIONS_IN_STRIP = 6;
259d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka
260d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        private final int mColorTypedWord;
261d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        private final int mColorAutoCorrect;
262d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        private final int mColorSuggestedCandidate;
263d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        private final int mCandidateCountInStrip;
26460a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka        private final float mCenterCandidateWeight;
26560a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka        private final int mCenterCandidateIndex;
266ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka        private final Drawable mMoreCandidateHint;
267d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka
268d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        private static final CharacterStyle BOLD_SPAN = new StyleSpan(Typeface.BOLD);
269d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        private static final CharacterStyle UNDERLINE_SPAN = new UnderlineSpan();
270d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        private final CharacterStyle mInvertedForegroundColorSpan;
271d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        private final CharacterStyle mInvertedBackgroundColorSpan;
272d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        private static final int AUTO_CORRECT_BOLD = 0x01;
273d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        private static final int AUTO_CORRECT_UNDERLINE = 0x02;
274d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        private static final int AUTO_CORRECT_INVERT = 0x04;
275d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka
27616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka        private final TextPaint mPaint;
27774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        private final int mAutoCorrectHighlight;
27874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
279d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        private final ArrayList<CharSequence> mTexts = new ArrayList<CharSequence>();
28074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
281ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka        public boolean mMoreSuggestionsAvailable;
282ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka
283d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        public SuggestionsStripParams(Context context, AttributeSet attrs, int defStyle,
284ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka                List<TextView> words, List<View> dividers, List<TextView> infos) {
285ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka            super(words, dividers, infos);
286d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            final TypedArray a = context.obtainStyledAttributes(
287d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka                    attrs, R.styleable.CandidateView, defStyle, R.style.CandidateViewStyle);
288d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            mAutoCorrectHighlight = a.getInt(R.styleable.CandidateView_autoCorrectHighlight, 0);
289d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            mColorTypedWord = a.getColor(R.styleable.CandidateView_colorTypedWord, 0);
290d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            mColorAutoCorrect = a.getColor(R.styleable.CandidateView_colorAutoCorrect, 0);
291d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            mColorSuggestedCandidate = a.getColor(R.styleable.CandidateView_colorSuggested, 0);
292d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            mCandidateCountInStrip = a.getInt(
293d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka                    R.styleable.CandidateView_candidateCountInStrip,
294d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka                    DEFAULT_CANDIDATE_COUNT_IN_STRIP);
29560a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            mCenterCandidateWeight = a.getInt(
29660a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                    R.styleable.CandidateView_centerCandidatePercentile,
29760a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                    DEFAULT_CENTER_CANDIDATE_PERCENTILE) / 100.0f;
298d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            a.recycle();
299d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka
30060a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            mCenterCandidateIndex = mCandidateCountInStrip / 2;
301ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka            final Resources res = context.getResources();
302ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka            mMoreCandidateHint = res.getDrawable(R.drawable.more_suggestions_hint);
30360a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka
304d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            mInvertedForegroundColorSpan = new ForegroundColorSpan(mColorTypedWord ^ 0x00ffffff);
305d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            mInvertedBackgroundColorSpan = new BackgroundColorSpan(mColorTypedWord);
306d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka
30774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            mPaint = new TextPaint();
308ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka            final float textSize = res.getDimension(R.dimen.candidate_text_size);
30974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            mPaint.setTextSize(textSize);
31074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        }
31174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
31216713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka        public int getTextColor() {
31316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka            return mColorTypedWord;
314d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        }
315d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka
31616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka        private CharSequence getStyledCandidateWord(CharSequence word, boolean isAutoCorrect) {
317d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            if (!isAutoCorrect)
318d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka                return word;
319d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            final int len = word.length();
320d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            final Spannable spannedWord = new SpannableString(word);
321d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            if ((mAutoCorrectHighlight & AUTO_CORRECT_BOLD) != 0)
322d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka                spannedWord.setSpan(BOLD_SPAN, 0, len, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
323d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            if ((mAutoCorrectHighlight & AUTO_CORRECT_UNDERLINE) != 0)
324d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka                spannedWord.setSpan(UNDERLINE_SPAN, 0, len, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
325d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            return spannedWord;
326d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        }
327d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka
32860a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka        private static boolean willAutoCorrect(SuggestedWords suggestions) {
32960a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            return !suggestions.mTypedWordValid && suggestions.mHasMinimalSuggestion;
33060a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka        }
33160a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka
33260a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka        private int getWordPosition(int index, SuggestedWords suggestions) {
33360a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            // TODO: This works for 3 suggestions. Revisit this algorithm when there are 5 or more
33460a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            // suggestions.
33560a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            final int centerPos = willAutoCorrect(suggestions) ? 1 : 0;
33660a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            if (index == mCenterCandidateIndex) {
33760a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                return centerPos;
33860a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            } else if (index == centerPos) {
33960a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                return mCenterCandidateIndex;
34060a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            } else {
341d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka                return index;
342d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            }
343d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        }
344d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka
34560a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka        private int getCandidateTextColor(int index, SuggestedWords suggestions, int pos) {
346d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            // TODO: Need to revisit this logic with bigram suggestions
347d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            final boolean isSuggestedCandidate = (pos != 0);
348d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka
349d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            final int color;
35060a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            if (index == mCenterCandidateIndex && willAutoCorrect(suggestions)) {
351d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka                color = mColorAutoCorrect;
352d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            } else if (isSuggestedCandidate) {
353d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka                color = mColorSuggestedCandidate;
354d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            } else {
355d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka                color = mColorTypedWord;
356d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            }
35760a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka
35860a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            final SuggestedWordInfo info = (pos < suggestions.size())
35960a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                    ? suggestions.getInfo(pos) : null;
360d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            if (info != null && info.isPreviousSuggestedWord()) {
361d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka                return applyAlpha(color, 0.5f);
362d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            } else {
363d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka                return color;
364d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            }
365d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        }
366d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka
367d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        private static int applyAlpha(final int color, final float alpha) {
368d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            final int newAlpha = (int)(Color.alpha(color) * alpha);
369d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            return Color.argb(newAlpha, Color.red(color), Color.green(color), Color.blue(color));
370d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        }
371d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka
372d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        public CharSequence getInvertedText(CharSequence text) {
373d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            if ((mAutoCorrectHighlight & AUTO_CORRECT_INVERT) == 0)
374d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka                return null;
375d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            final int len = text.length();
376d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            final Spannable word = new SpannableString(text);
377d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            word.setSpan(mInvertedBackgroundColorSpan, 0, len, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
378d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            word.setSpan(mInvertedForegroundColorSpan, 0, len, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
379d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            return word;
380d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        }
381d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka
38216713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka        public int layout(SuggestedWords suggestions, ViewGroup stripView, ViewGroup paneView,
38316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                int stripWidth) {
38460a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            if (suggestions.isPunctuationSuggestions()) {
38560a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                return layoutPunctuationSuggestions(suggestions, stripView);
38660a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            }
38760a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka
38860a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            final int countInStrip = mCandidateCountInStrip;
38960a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            setupTexts(suggestions, countInStrip);
39060a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka
39160a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            int x = 0;
39260a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            for (int index = 0; index < countInStrip; index++) {
39360a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                final int pos = getWordPosition(index, suggestions);
39460a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka
39560a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                if (index != 0) {
39660a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                    final View divider = mDividers.get(pos);
39760a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                    // Add divider if this isn't the left most suggestion in candidate strip.
39860a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                    stripView.addView(divider);
39960a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                }
40060a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka
40116713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                final CharSequence styled = mTexts.get(pos);
40260a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                final TextView word = mWords.get(pos);
403ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka                if (index == mCenterCandidateIndex && suggestions.size() > countInStrip) {
404ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka                    // TODO: This "more suggestions hint" should have nicely designed icon.
405ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka                    word.setCompoundDrawablesWithIntrinsicBounds(
406ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka                            null, null, null, mMoreCandidateHint);
407ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka                    mMoreSuggestionsAvailable = true;
408ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka                } else {
409ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka                    word.setCompoundDrawables(null, null, null, null);
410ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka                    mMoreSuggestionsAvailable = false;
411ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka                }
412ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka
41360a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                // Disable this candidate if the suggestion is null or empty.
41460a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                word.setEnabled(!TextUtils.isEmpty(styled));
41560a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                word.setTextColor(getCandidateTextColor(index, suggestions, pos));
416ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka                final int width = getCandidateWidth(index, stripWidth);
41760a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                final CharSequence text = getEllipsizedText(styled, width, word.getPaint());
41860a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                final float scaleX = word.getTextScaleX();
41960a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                word.setText(text); // TextView.setText() resets text scale x to 1.0.
42060a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                word.setTextScaleX(scaleX);
42160a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                stripView.addView(word);
42260a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                setLayoutWeight(word, getCandidateWeight(index), mCandidateStripHeight);
42316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka
42416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                if (DBG) {
42560a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                    final CharSequence debugInfo = getDebugInfo(suggestions, pos);
42616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    if (debugInfo != null) {
42760a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                        final TextView info = mInfos.get(pos);
42816713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                        info.setText(debugInfo);
42916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                        paneView.addView(info);
43016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                        info.measure(WRAP_CONTENT, WRAP_CONTENT);
43160a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                        final int infoWidth = info.getMeasuredWidth();
43216713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                        final int y = info.getMeasuredHeight();
43360a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                        FrameLayoutCompatUtils.placeViewAt(info, x, 0, infoWidth, y);
43460a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                        x += infoWidth * 2;
43516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    }
43660a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                }
43716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka            }
43816713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka
43960a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            return countInStrip;
44016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka        }
44116713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka
44260a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka        private int getCandidateWidth(int index, int maxWidth) {
44360a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            final int paddings = mPadding * mCandidateCountInStrip;
44460a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            final int dividers = mDividerWidth * (mCandidateCountInStrip - 1);
44560a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            final int availableWidth = maxWidth - paddings - dividers;
44660a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            return (int)(availableWidth * getCandidateWeight(index));
44760a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka        }
44874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
44960a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka        private float getCandidateWeight(int index) {
45060a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            if (index == mCenterCandidateIndex) {
45160a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                return mCenterCandidateWeight;
45260a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            } else {
45360a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                // TODO: Revisit this for cases of 5 or more suggestions
45460a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                return (1.0f - mCenterCandidateWeight) / (mCandidateCountInStrip - 1);
45574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            }
45674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        }
45774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
45860a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka        private void setupTexts(SuggestedWords suggestions, int countInStrip) {
45974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            mTexts.clear();
46060a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            final int count = Math.min(suggestions.size(), countInStrip);
46160a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            for (int pos = 0; pos < count; pos++) {
46260a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                final CharSequence word = suggestions.getWord(pos);
46360a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                final boolean isAutoCorrect = pos == 1 && willAutoCorrect(suggestions);
464d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka                final CharSequence styled = getStyledCandidateWord(word, isAutoCorrect);
46574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                mTexts.add(styled);
46674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            }
46760a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            for (int pos = count; pos < countInStrip; pos++) {
46860a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                // Make this inactive for touches in layout().
46960a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                mTexts.add(null);
47060a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            }
47174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        }
47274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
47360a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka        private int layoutPunctuationSuggestions(SuggestedWords suggestions, ViewGroup stripView) {
47460a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            final int countInStrip = Math.min(suggestions.size(), PUNCTUATIONS_IN_STRIP);
47560a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            for (int index = 0; index < countInStrip; index++) {
47660a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                if (index != 0) {
47760a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                    // Add divider if this isn't the left most suggestion in candidate strip.
47860a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                    stripView.addView(mDividers.get(index));
47960a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                }
48060a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka
48160a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                final TextView word = mWords.get(index);
48260a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                word.setEnabled(true);
48360a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                word.setTextColor(mColorTypedWord);
48460a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                final CharSequence text = suggestions.getWord(index);
48560a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                word.setText(text);
48660a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                word.setTextScaleX(1.0f);
487ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka                word.setCompoundDrawables(null, null, null, null);
48860a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                stripView.addView(word);
48960a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                setLayoutWeight(word, 1.0f, mCandidateStripHeight);
49060a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            }
491ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka            mMoreSuggestionsAvailable = false;
49260a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            return countInStrip;
49374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        }
49474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka    }
49574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
496923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    /**
497923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     * Construct a CandidateView for showing suggested words for completion.
498923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     * @param context
499923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     * @param attrs
500923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     */
501923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public CandidateView(Context context, AttributeSet attrs) {
50208a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka        this(context, attrs, R.attr.candidateViewStyle);
50308a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka    }
50408a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka
50508a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka    public CandidateView(Context context, AttributeSet attrs, int defStyle) {
506f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka        // Note: Up to version 10 (Gingerbread) of the API, LinearLayout doesn't have 3-argument
507f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka        // constructor.
508f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka        // TODO: Call 3-argument constructor, super(context, attrs, defStyle), when we abandon
509f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka        // backward compatibility with the version 10 or earlier of the API.
510f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka        super(context, attrs);
511f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka        if (defStyle != R.attr.candidateViewStyle) {
512f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka            throw new IllegalArgumentException(
513f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka                    "can't accept defStyle other than R.attr.candidayeViewStyle: defStyle="
514f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka                    + defStyle);
515f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka        }
516f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka        setBackgroundDrawable(LinearLayoutCompatUtils.getBackgroundDrawable(
517f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka                context, attrs, defStyle, R.style.CandidateViewStyle));
518923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
51916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka        final LayoutInflater inflater = LayoutInflater.from(context);
52086e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        inflater.inflate(R.layout.candidates_strip, this);
52186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka
52286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        mPreviewPopup = new PopupWindow(context);
523e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        mPreviewText = (TextView) inflater.inflate(R.layout.candidate_preview, null);
524e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        mPreviewPopup.setWindowLayoutMode(ViewGroup.LayoutParams.WRAP_CONTENT,
525e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                ViewGroup.LayoutParams.WRAP_CONTENT);
526923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mPreviewPopup.setContentView(mPreviewText);
527923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mPreviewPopup.setBackgroundDrawable(null);
528923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
52974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        mCandidatesStrip = (ViewGroup)findViewById(R.id.candidates_strip);
53060a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka        for (int pos = 0; pos < MAX_SUGGESTIONS; pos++) {
53174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            final TextView word = (TextView)inflater.inflate(R.layout.candidate_word, null);
53260a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            word.setTag(pos);
5332442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka            word.setOnClickListener(this);
534ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka            word.setOnLongClickListener(this);
5352442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka            mWords.add(word);
536a1aab83a24e74cb0fad4b1c1e59b18d23ecbdad3Tadashi G. Takaoka            final View divider = inflater.inflate(R.layout.candidate_divider, null);
53760a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            divider.setTag(pos);
538a1aab83a24e74cb0fad4b1c1e59b18d23ecbdad3Tadashi G. Takaoka            divider.setOnClickListener(this);
539a1aab83a24e74cb0fad4b1c1e59b18d23ecbdad3Tadashi G. Takaoka            mDividers.add(divider);
54074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            mInfos.add((TextView)inflater.inflate(R.layout.candidate_info, null));
541c9716b28ce438e06b5cacc07fc002944bcbe24a0Tadashi G. Takaoka        }
542179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaoka
543717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka        mTouchToSave = findViewById(R.id.touch_to_save);
544717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka        mWordToSave = (TextView)findViewById(R.id.word_to_save);
545717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka        mWordToSave.setOnClickListener(this);
546717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka
547ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka        mStripParams = new SuggestionsStripParams(context, attrs, defStyle, mWords, mDividers,
548ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka                mInfos);
549ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka        mPaneParams = new SuggestionsPaneParams(mWords, mDividers, mInfos);
550923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
551c9716b28ce438e06b5cacc07fc002944bcbe24a0Tadashi G. Takaoka
552923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    /**
553c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka     * A connection back to the input method.
554923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     * @param listener
555923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     */
55686e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka    public void setListener(Listener listener, View inputView) {
557c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka        mListener = listener;
55886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        mKeyboardView = inputView.findViewById(R.id.keyboard_view);
559a7eed902f1b0d6871d416412b3c6f91163fa2578Tadashi G. Takaoka        mCandidatesPane = FrameLayoutCompatUtils.getPlacer(
560a7eed902f1b0d6871d416412b3c6f91163fa2578Tadashi G. Takaoka                (ViewGroup)inputView.findViewById(R.id.candidates_pane));
56186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        mCandidatesPane.setOnClickListener(this);
56286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        mCandidatesPaneContainer = (ViewGroup)inputView.findViewById(
56386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka                R.id.candidates_pane_container);
564923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
565923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
5667e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka    public void setSuggestions(SuggestedWords suggestions) {
5679fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if (suggestions == null)
568a15e45ef45931ba46678b39c159518d8aa2d4d65Tadashi G. Takaoka            return;
5699fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        mSuggestions = suggestions;
57055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        if (mShowingAutoCorrectionInverted) {
5719fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            mHandler.postUpdateSuggestions();
57255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        } else {
5739fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            updateSuggestions();
57455b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        }
57555b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka    }
57655b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka
5779fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka    private void updateSuggestions() {
578e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        clear();
57986e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        closeCandidatesPane();
58016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka        if (mSuggestions.size() == 0)
58174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            return;
58274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
58316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka        final int width = getWidth();
58416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka        final int countInStrip = mStripParams.layout(
58516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                mSuggestions, mCandidatesStrip, mCandidatesPane, width);
58616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka        final int countInPane = mPaneParams.layout(
58716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                mSuggestions, mCandidatesPane, countInStrip, mStripParams.getTextColor(), width);
58816713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka    }
58974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
59016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka    private static CharSequence getDebugInfo(SuggestedWords suggestions, int pos) {
59160a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka        if (DBG && pos < suggestions.size()) {
59216713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka            final SuggestedWordInfo wordInfo = suggestions.getInfo(pos);
59316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka            if (wordInfo != null) {
59416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                final CharSequence debugInfo = wordInfo.getDebugString();
59516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                if (!TextUtils.isEmpty(debugInfo)) {
59616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    return debugInfo;
597d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka                }
5982442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka            }
59986e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        }
60016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka        return null;
60186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka    }
60286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka
6033118277dd47492089761c0ed1097abaeb376395cTadashi G. Takaoka    private static void setLayoutWeight(View v, float weight, int height) {
60474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        final ViewGroup.LayoutParams lp = v.getLayoutParams();
60574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        if (lp instanceof LinearLayout.LayoutParams) {
60674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            final LinearLayout.LayoutParams llp = (LinearLayout.LayoutParams)lp;
60774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            llp.weight = weight;
60874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            llp.width = 0;
6093118277dd47492089761c0ed1097abaeb376395cTadashi G. Takaoka            llp.height = height;
61074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        }
61174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka    }
61274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
61316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka    private static void centeringCandidates(ViewGroup parent, View from, View to, int width,
61416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka            int parentWidth) {
61516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka        final int fromIndex = parent.indexOfChild(from);
61616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka        final int toIndex = parent.indexOfChild(to);
61716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka        final int offset = (parentWidth - width) / 2;
61886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        for (int index = fromIndex; index <= toIndex; index++) {
61916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka            offsetMargin(parent.getChildAt(index), offset, 0);
62086e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        }
62186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka    }
62286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka
62386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka    private static void offsetMargin(View v, int dx, int dy) {
624862e05a8f0aa03ddc4582d5bf68a3201f348cf1dTadashi G. Takaoka        if (v == null)
625862e05a8f0aa03ddc4582d5bf68a3201f348cf1dTadashi G. Takaoka            return;
6262442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka        final ViewGroup.LayoutParams lp = v.getLayoutParams();
62786e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        if (lp instanceof ViewGroup.MarginLayoutParams) {
6282442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka            final ViewGroup.MarginLayoutParams mlp = (ViewGroup.MarginLayoutParams)lp;
62986e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka            mlp.setMargins(mlp.leftMargin + dx, mlp.topMargin + dy, 0, 0);
63086e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        }
63186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka    }
63286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka
63374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka    private static CharSequence getEllipsizedText(CharSequence text, int maxWidth,
63474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            TextPaint paint) {
63574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        paint.setTextScaleX(1.0f);
63674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        final int width = getTextWidth(text, paint);
63760a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka        if (width <= maxWidth) {
63860a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            return text;
63960a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka        }
64060a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka        final float scaleX = maxWidth / (float)width;
641b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka        if (scaleX >= MIN_TEXT_XSCALE) {
64274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            paint.setTextScaleX(scaleX);
64374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            return text;
644b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka        }
645b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka
64674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        // Note that TextUtils.ellipsize() use text-x-scale as 1.0 if ellipsize is needed. To get
64760a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka        // squeezed and ellipsized text, passes enlarged width (maxWidth / MIN_TEXT_XSCALE).
64874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        final CharSequence ellipsized = TextUtils.ellipsize(
64974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                text, paint, maxWidth / MIN_TEXT_XSCALE, TextUtils.TruncateAt.MIDDLE);
65074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        paint.setTextScaleX(MIN_TEXT_XSCALE);
65174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        return ellipsized;
652b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka    }
653b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka
65474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka    private static int getTextWidth(CharSequence text, TextPaint paint) {
655b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka        if (TextUtils.isEmpty(text)) return 0;
656fe9b65afa84530d17dd82c770c19de763a50cb58Tadashi G. Takaoka        final Typeface savedTypeface = paint.getTypeface();
65774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        paint.setTypeface(getTextTypeface(text));
658b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka        final int len = text.length();
659b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka        final float[] widths = new float[len];
660b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka        final int count = paint.getTextWidths(text, 0, len, widths);
661fe9b65afa84530d17dd82c770c19de763a50cb58Tadashi G. Takaoka        int width = 0;
662b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka        for (int i = 0; i < count; i++) {
663fe9b65afa84530d17dd82c770c19de763a50cb58Tadashi G. Takaoka            width += Math.round(widths[i] + 0.5f);
664b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka        }
665fe9b65afa84530d17dd82c770c19de763a50cb58Tadashi G. Takaoka        paint.setTypeface(savedTypeface);
666fe9b65afa84530d17dd82c770c19de763a50cb58Tadashi G. Takaoka        return width;
667b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka    }
668b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka
66974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka    private static Typeface getTextTypeface(CharSequence text) {
67074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        if (!(text instanceof SpannableString))
67174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            return Typeface.DEFAULT;
67274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
67374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        final SpannableString ss = (SpannableString)text;
67474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        final StyleSpan[] styles = ss.getSpans(0, text.length(), StyleSpan.class);
67574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        if (styles.length == 0)
67674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            return Typeface.DEFAULT;
67774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
67874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        switch (styles[0].getStyle()) {
67974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        case Typeface.BOLD: return Typeface.DEFAULT_BOLD;
68074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        // TODO: BOLD_ITALIC, ITALIC case?
68174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        default: return Typeface.DEFAULT;
682b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka        }
683b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka    }
684b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka
68586e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka    private void expandCandidatesPane() {
68686e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        mCandidatesPaneContainer.setMinimumHeight(mKeyboardView.getMeasuredHeight());
68774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        mCandidatesPaneContainer.setVisibility(VISIBLE);
68874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        mKeyboardView.setVisibility(GONE);
68986e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka    }
690e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka
69186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka    private void closeCandidatesPane() {
69274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        mCandidatesPaneContainer.setVisibility(GONE);
69374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        mKeyboardView.setVisibility(VISIBLE);
694923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
695923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
69655b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka    public void onAutoCorrectionInverted(CharSequence autoCorrectedWord) {
697d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        final CharSequence inverted = mStripParams.getInvertedText(autoCorrectedWord);
698d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        if (inverted == null)
69955b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            return;
7001e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka        final TextView tv = mWords.get(1);
701d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        tv.setText(inverted);
70255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        mShowingAutoCorrectionInverted = true;
70355b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka    }
70455b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka
705b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani    public boolean isShowingAddToDictionaryHint() {
706b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        return mShowingAddToDictionary;
707b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani    }
708b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani
70966a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani    public void showAddToDictionaryHint(CharSequence word) {
710717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka        mWordToSave.setText(word);
71166a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani        mShowingAddToDictionary = true;
71274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        mCandidatesStrip.setVisibility(GONE);
71374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        mTouchToSave.setVisibility(VISIBLE);
71466a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani    }
71566a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani
7166558253160e2039c87f424bd814f402ecd31de3bKen Wakasa    public boolean dismissAddToDictionaryHint() {
7176558253160e2039c87f424bd814f402ecd31de3bKen Wakasa        if (!mShowingAddToDictionary) return false;
7186558253160e2039c87f424bd814f402ecd31de3bKen Wakasa        clear();
7196558253160e2039c87f424bd814f402ecd31de3bKen Wakasa        return true;
7206558253160e2039c87f424bd814f402ecd31de3bKen Wakasa    }
7216558253160e2039c87f424bd814f402ecd31de3bKen Wakasa
7227e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka    public SuggestedWords getSuggestions() {
723979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        return mSuggestions;
724979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
725979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
726923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void clear() {
72766a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani        mShowingAddToDictionary = false;
72855b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        mShowingAutoCorrectionInverted = false;
72974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        mTouchToSave.setVisibility(GONE);
7301bd62a56211db2933eb5dd735c108e610111d6fbKen Wakasa        mCandidatesStrip.setVisibility(VISIBLE);
73174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        mCandidatesStrip.removeAllViews();
73286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        mCandidatesPane.removeAllViews();
73388110d1799146943c627916ffaa94bbc4dd6f2aeTadashi G. Takaoka        closeCandidatesPane();
734923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
735923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
7366ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani    private void hidePreview() {
737179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaoka        mPreviewPopup.dismiss();
7386ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani    }
739e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka
740e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka    private void showPreview(int index, CharSequence word) {
741e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        if (TextUtils.isEmpty(word))
742e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka            return;
743e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka
744e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        final TextView previewText = mPreviewText;
745d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        previewText.setTextColor(mStripParams.mColorTypedWord);
746e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        previewText.setText(word);
747e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        previewText.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
748e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka                MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
749f20eb55d4f8063f89c6c0abb3af3029fe23cb845Tadashi G. Takaoka        View v = mWords.get(index);
750e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        final int[] offsetInWindow = new int[2];
751e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        v.getLocationInWindow(offsetInWindow);
752e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        final int posX = offsetInWindow[0];
753e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        final int posY = offsetInWindow[1] - previewText.getMeasuredHeight();
754e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        final PopupWindow previewPopup = mPreviewPopup;
755e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        if (previewPopup.isShowing()) {
756e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka            previewPopup.update(posX, posY, previewPopup.getWidth(), previewPopup.getHeight());
757e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        } else {
758e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka            previewPopup.showAtLocation(this, Gravity.NO_GRAVITY, posX, posY);
759923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
760e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        previewText.setVisibility(VISIBLE);
76155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        mHandler.postHidePreview();
762923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
763fcba53ef7c874a4685c12c01404c91b779cae1e8Tadashi G. Takaoka
764e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka    private void addToDictionary(CharSequence word) {
765c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka        if (mListener.addWordToDictionary(word.toString())) {
766e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka            showPreview(0, getContext().getString(R.string.added_word, word));
767e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        }
768e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka    }
769e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka
770e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka    @Override
771ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka    public boolean onLongClick(View view) {
772ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka        if (mStripParams.mMoreSuggestionsAvailable) {
773ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka            expandCandidatesPane();
774ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka            return true;
775ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka        }
776ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka        return false;
777ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka    }
778ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka
779ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka    @Override
780e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka    public void onClick(View view) {
781717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka        if (view == mWordToSave) {
782717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka            addToDictionary(((TextView)view).getText());
783717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka            clear();
784717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka            return;
785717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka        }
786717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka
787ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka        if (view == mCandidatesPane) {
788ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka            closeCandidatesPane();
789ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka            return;
790ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka        }
791ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka
79286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        final Object tag = view.getTag();
79386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        if (!(tag instanceof Integer))
79486e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka            return;
79586e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        final int index = (Integer) tag;
79637deb112c727dfed5e94d054cf5f00f5d60c8120Tadashi G. Takaoka        if (index >= mSuggestions.size())
79737deb112c727dfed5e94d054cf5f00f5d60c8120Tadashi G. Takaoka            return;
79886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka
79937deb112c727dfed5e94d054cf5f00f5d60c8120Tadashi G. Takaoka        final CharSequence word = mSuggestions.getWord(index);
800717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka        mListener.pickSuggestionManually(index, word);
80186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        // Because some punctuation letters are not treated as word separator depending on locale,
80286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        // {@link #setSuggestions} might not be called and candidates pane left opened.
80386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        closeCandidatesPane();
804923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
80582411d47ba7e8133ed2390c6920945e139a738cesatok
8066ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani    @Override
8076ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani    public void onDetachedFromWindow() {
8086ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani        super.onDetachedFromWindow();
80955b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        mHandler.cancelAllMessages();
8106ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani        hidePreview();
8116ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani    }
812923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project}
813