SuggestionStripView.java revision 8ac6d505b7ceab020a4085b3dfbea5b47362b030
1923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project/*
2913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka * Copyright (C) 2011 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;
2629e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaokaimport android.os.SystemClock;
27522d5c16d20657e7d26009fe9c067404e16a6c2aTadashi G. Takaokaimport android.text.Spannable;
28522d5c16d20657e7d26009fe9c067404e16a6c2aTadashi G. Takaokaimport android.text.SpannableString;
29e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaokaimport android.text.Spanned;
30b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaokaimport android.text.TextPaint;
31e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaokaimport android.text.TextUtils;
3255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaokaimport android.text.style.BackgroundColorSpan;
33522d5c16d20657e7d26009fe9c067404e16a6c2aTadashi G. Takaokaimport android.text.style.CharacterStyle;
3455b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaokaimport android.text.style.ForegroundColorSpan;
3574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaokaimport android.text.style.StyleSpan;
36522d5c16d20657e7d26009fe9c067404e16a6c2aTadashi G. Takaokaimport android.text.style.UnderlineSpan;
37923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.util.AttributeSet;
38923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.Gravity;
39923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.LayoutInflater;
4029e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaokaimport android.view.MotionEvent;
41923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.View;
42e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaokaimport android.view.View.OnClickListener;
43ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaokaimport android.view.View.OnLongClickListener;
44e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaokaimport android.view.ViewGroup;
45e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaokaimport android.widget.LinearLayout;
46923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.widget.PopupWindow;
47c412309b7a32308b1b0a175dafc13f90254353c5Tadashi G. Takaokaimport android.widget.RelativeLayout;
48923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.widget.TextView;
49923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
50a7eed902f1b0d6871d416412b3c6f91163fa2578Tadashi G. Takaokaimport com.android.inputmethod.compat.FrameLayoutCompatUtils;
5129e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaokaimport com.android.inputmethod.keyboard.KeyboardActionListener;
521b087064c07975c5e2b9c17d4ca80c56e01c35c0Tadashi G. Takaokaimport com.android.inputmethod.keyboard.KeyboardView;
5329e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaokaimport com.android.inputmethod.keyboard.MoreKeysPanel;
5429e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaokaimport com.android.inputmethod.keyboard.PointerTracker;
55ddb61ea461b920d87be4ad78c8a36eec1013b965Tadashi G. Takaokaimport com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
56ddb61ea461b920d87be4ad78c8a36eec1013b965Tadashi G. Takaoka
57179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaokaimport java.util.ArrayList;
586f7218627eda110a8454053f8ecb7b80edfdc8cesatokimport java.util.List;
59179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaoka
60c412309b7a32308b1b0a175dafc13f90254353c5Tadashi G. Takaokapublic class SuggestionsView extends RelativeLayout implements OnClickListener,
61c412309b7a32308b1b0a175dafc13f90254353c5Tadashi G. Takaoka        OnLongClickListener {
62c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka    public interface Listener {
63c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka        public boolean addWordToDictionary(String word);
64c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka        public void pickSuggestionManually(int index, CharSequence word);
65c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka    }
66c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka
6786e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka    // The maximum number of suggestions available. See {@link Suggest#mPrefMaxSuggestions}.
6829e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka    public static final int MAX_SUGGESTIONS = 18;
69923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
708553b5ec315660ab53dd9234e64e1e39ea09ec0fJean Chalard    private static final boolean DBG = LatinImeLogger.sDBG;
716f7218627eda110a8454053f8ecb7b80edfdc8cesatok
72913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka    private final ViewGroup mSuggestionsStrip;
731b087064c07975c5e2b9c17d4ca80c56e01c35c0Tadashi G. Takaoka    private KeyboardView mKeyboardView;
7474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
7529e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka    private final View mMoreSuggestionsContainer;
7629e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka    private final MoreSuggestionsView mMoreSuggestionsView;
7729e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka    private final MoreSuggestions.Builder mMoreSuggestionsBuilder;
7829e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka    private final PopupWindow mMoreSuggestionsWindow;
7929e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka
801e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka    private final ArrayList<TextView> mWords = new ArrayList<TextView>();
812442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka    private final ArrayList<TextView> mInfos = new ArrayList<TextView>();
82ddb61ea461b920d87be4ad78c8a36eec1013b965Tadashi G. Takaoka    private final ArrayList<View> mDividers = new ArrayList<View>();
8374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
8482411d47ba7e8133ed2390c6920945e139a738cesatok    private final PopupWindow mPreviewPopup;
8582411d47ba7e8133ed2390c6920945e139a738cesatok    private final TextView mPreviewText;
8666a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani
87c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka    private Listener mListener;
887e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka    private SuggestedWords mSuggestions = SuggestedWords.EMPTY;
8955b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka    private boolean mShowingAutoCorrectionInverted;
906a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani
91d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka    private final SuggestionsViewParams mParams;
92ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka    private static final float MIN_TEXT_XSCALE = 0.70f;
93b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka
944f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa    private final UiHandler mHandler = new UiHandler(this);
9555b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka
96913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka    private static class UiHandler extends StaticInnerHandlerWrapper<SuggestionsView> {
9755b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        private static final int MSG_HIDE_PREVIEW = 0;
9855b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        private static final int MSG_UPDATE_SUGGESTION = 1;
9955b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka
100c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka        private static final long DELAY_HIDE_PREVIEW = 1300;
10155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        private static final long DELAY_UPDATE_SUGGESTION = 300;
10255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka
103913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka        public UiHandler(SuggestionsView outerInstance) {
1044f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa            super(outerInstance);
1054f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa        }
1064f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa
107e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        @Override
108e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        public void dispatchMessage(Message msg) {
109913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka            final SuggestionsView suggestionsView = getOuterInstance();
110e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka            switch (msg.what) {
111e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka            case MSG_HIDE_PREVIEW:
112913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka                suggestionsView.hidePreview();
113e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka                break;
11455b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            case MSG_UPDATE_SUGGESTION:
115913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka                suggestionsView.updateSuggestions();
11655b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka                break;
117e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka            }
118e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        }
11955b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka
12055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        public void postHidePreview() {
12155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            cancelHidePreview();
12255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            sendMessageDelayed(obtainMessage(MSG_HIDE_PREVIEW), DELAY_HIDE_PREVIEW);
12355b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        }
12455b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka
12555b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        public void cancelHidePreview() {
12655b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            removeMessages(MSG_HIDE_PREVIEW);
12755b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        }
12855b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka
1299fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        public void postUpdateSuggestions() {
13055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            cancelUpdateSuggestions();
1319fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            sendMessageDelayed(obtainMessage(MSG_UPDATE_SUGGESTION),
13255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka                    DELAY_UPDATE_SUGGESTION);
13355b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        }
13455b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka
13555b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        public void cancelUpdateSuggestions() {
13655b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            removeMessages(MSG_UPDATE_SUGGESTION);
13755b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        }
13855b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka
13955b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        public void cancelAllMessages() {
14055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            cancelHidePreview();
14155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            cancelUpdateSuggestions();
14255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        }
143e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka    }
144179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaoka
145913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka    private static class SuggestionsViewParams {
146d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka        private static final int DEFAULT_SUGGESTIONS_COUNT_IN_STRIP = 3;
147d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka        private static final int DEFAULT_CENTER_SUGGESTION_PERCENTILE = 40;
1489676038b6e9fb66760588d7f9c9c642cc493dd71Tadashi G. Takaoka        private static final int DEFAULT_MAX_MORE_SUGGESTIONS_ROW = 2;
149d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka        private static final int PUNCTUATIONS_IN_STRIP = 6;
150d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka
15174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        public final int mPadding;
15274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        public final int mDividerWidth;
153913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka        public final int mSuggestionsStripHeight;
154d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka        public final int mSuggestionsCountInStrip;
1559676038b6e9fb66760588d7f9c9c642cc493dd71Tadashi G. Takaoka        public final int mMaxMoreSuggestionsRow;
1569676038b6e9fb66760588d7f9c9c642cc493dd71Tadashi G. Takaoka        public final float mMinMoreSuggestionsWidth;
15716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka
158d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka        private final List<TextView> mWords;
159d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka        private final List<View> mDividers;
160d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka        private final List<TextView> mInfos;
161d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka
162d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        private final int mColorTypedWord;
163d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        private final int mColorAutoCorrect;
164913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka        private final int mColorSuggested;
165913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka        private final float mCenterSuggestionWeight;
166913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka        private final int mCenterSuggestionIndex;
167913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka        private final Drawable mMoreSuggestionsHint;
168d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka
169d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        private static final CharacterStyle BOLD_SPAN = new StyleSpan(Typeface.BOLD);
170d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        private static final CharacterStyle UNDERLINE_SPAN = new UnderlineSpan();
171d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        private final CharacterStyle mInvertedForegroundColorSpan;
172d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        private final CharacterStyle mInvertedBackgroundColorSpan;
173d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        private static final int AUTO_CORRECT_BOLD = 0x01;
174d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        private static final int AUTO_CORRECT_UNDERLINE = 0x02;
175d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        private static final int AUTO_CORRECT_INVERT = 0x04;
176d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka        private static final int VALID_TYPED_WORD_BOLD = 0x08;
177d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka
178d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka        private final int mSuggestionStripOption;
17974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
180d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        private final ArrayList<CharSequence> mTexts = new ArrayList<CharSequence>();
18174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
182ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka        public boolean mMoreSuggestionsAvailable;
183ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka
184c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka        public final TextView mWordToSaveView;
185c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka        private final TextView mHintToSaveView;
186c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka        private final CharSequence mHintToSaveText;
187c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka
188d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka        public SuggestionsViewParams(Context context, AttributeSet attrs, int defStyle,
189ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka                List<TextView> words, List<View> dividers, List<TextView> infos) {
190d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka            mWords = words;
191d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka            mDividers = dividers;
192d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka            mInfos = infos;
193d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka
194d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka            final TextView word = words.get(0);
195d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka            final View divider = dividers.get(0);
196d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka            mPadding = word.getCompoundPaddingLeft() + word.getCompoundPaddingRight();
197d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka            divider.measure(
198d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka                    ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
199d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka            mDividerWidth = divider.getMeasuredWidth();
200d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka
201d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka            final Resources res = word.getResources();
202d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka            mSuggestionsStripHeight = res.getDimensionPixelSize(R.dimen.suggestions_strip_height);
203d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka
204d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            final TypedArray a = context.obtainStyledAttributes(
205913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka                    attrs, R.styleable.SuggestionsView, defStyle, R.style.SuggestionsViewStyle);
206913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka            mSuggestionStripOption = a.getInt(R.styleable.SuggestionsView_suggestionStripOption, 0);
207913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka            mColorTypedWord = a.getColor(R.styleable.SuggestionsView_colorTypedWord, 0);
208913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka            mColorAutoCorrect = a.getColor(R.styleable.SuggestionsView_colorAutoCorrect, 0);
209913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka            mColorSuggested = a.getColor(R.styleable.SuggestionsView_colorSuggested, 0);
210913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka            mSuggestionsCountInStrip = a.getInt(
211913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka                    R.styleable.SuggestionsView_suggestionsCountInStrip,
212913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka                    DEFAULT_SUGGESTIONS_COUNT_IN_STRIP);
213913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka            mCenterSuggestionWeight = a.getInt(
214913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka                    R.styleable.SuggestionsView_centerSuggestionPercentile,
215913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka                    DEFAULT_CENTER_SUGGESTION_PERCENTILE) / 100.0f;
2169676038b6e9fb66760588d7f9c9c642cc493dd71Tadashi G. Takaoka            mMaxMoreSuggestionsRow = a.getInt(
2179676038b6e9fb66760588d7f9c9c642cc493dd71Tadashi G. Takaoka                    R.styleable.SuggestionsView_maxMoreSuggestionsRow,
2189676038b6e9fb66760588d7f9c9c642cc493dd71Tadashi G. Takaoka                    DEFAULT_MAX_MORE_SUGGESTIONS_ROW);
2199676038b6e9fb66760588d7f9c9c642cc493dd71Tadashi G. Takaoka            mMinMoreSuggestionsWidth = getRatio(a,
2209676038b6e9fb66760588d7f9c9c642cc493dd71Tadashi G. Takaoka                    R.styleable.SuggestionsView_minMoreSuggestionsWidth);
221d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            a.recycle();
222d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka
223913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka            mCenterSuggestionIndex = mSuggestionsCountInStrip / 2;
224913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka            mMoreSuggestionsHint = res.getDrawable(R.drawable.more_suggestions_hint);
22560a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka
226d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            mInvertedForegroundColorSpan = new ForegroundColorSpan(mColorTypedWord ^ 0x00ffffff);
227d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            mInvertedBackgroundColorSpan = new BackgroundColorSpan(mColorTypedWord);
228d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka
229c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            final LayoutInflater inflater = LayoutInflater.from(context);
230913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka            mWordToSaveView = (TextView)inflater.inflate(R.layout.suggestion_word, null);
231913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka            mHintToSaveView = (TextView)inflater.inflate(R.layout.suggestion_word, null);
232c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            mHintToSaveText = context.getText(R.string.hint_add_to_dictionary);
23374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        }
23474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
2359676038b6e9fb66760588d7f9c9c642cc493dd71Tadashi G. Takaoka        // Read fraction value in TypedArray as float.
2369676038b6e9fb66760588d7f9c9c642cc493dd71Tadashi G. Takaoka        private static float getRatio(TypedArray a, int index) {
2379676038b6e9fb66760588d7f9c9c642cc493dd71Tadashi G. Takaoka            return a.getFraction(index, 1000, 1000, 1) / 1000.0f;
2389676038b6e9fb66760588d7f9c9c642cc493dd71Tadashi G. Takaoka        }
2399676038b6e9fb66760588d7f9c9c642cc493dd71Tadashi G. Takaoka
240913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka        private CharSequence getStyledSuggestionWord(SuggestedWords suggestions, int pos) {
241d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka            final CharSequence word = suggestions.getWord(pos);
242d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka            final boolean isAutoCorrect = pos == 1 && willAutoCorrect(suggestions);
243d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka            final boolean isTypedWordValid = pos == 0 && suggestions.mTypedWordValid;
244d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka            if (!isAutoCorrect && !isTypedWordValid)
245d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka                return word;
246d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka
247d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            final int len = word.length();
248d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            final Spannable spannedWord = new SpannableString(word);
249d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka            final int option = mSuggestionStripOption;
250d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka            if ((isAutoCorrect && (option & AUTO_CORRECT_BOLD) != 0)
251d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka                    || (isTypedWordValid && (option & VALID_TYPED_WORD_BOLD) != 0)) {
252d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka                spannedWord.setSpan(BOLD_SPAN, 0, len, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
253d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka            }
254d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka            if (isAutoCorrect && (option & AUTO_CORRECT_UNDERLINE) != 0) {
255d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka                spannedWord.setSpan(UNDERLINE_SPAN, 0, len, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
256d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka            }
257d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            return spannedWord;
258d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        }
259d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka
26060a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka        private static boolean willAutoCorrect(SuggestedWords suggestions) {
26160a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            return !suggestions.mTypedWordValid && suggestions.mHasMinimalSuggestion;
26260a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka        }
26360a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka
26460a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka        private int getWordPosition(int index, SuggestedWords suggestions) {
26560a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            // TODO: This works for 3 suggestions. Revisit this algorithm when there are 5 or more
26660a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            // suggestions.
26760a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            final int centerPos = willAutoCorrect(suggestions) ? 1 : 0;
268913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka            if (index == mCenterSuggestionIndex) {
26960a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                return centerPos;
27060a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            } else if (index == centerPos) {
271913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka                return mCenterSuggestionIndex;
27260a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            } else {
273d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka                return index;
274d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            }
275d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        }
276d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka
277913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka        private int getSuggestionTextColor(int index, SuggestedWords suggestions, int pos) {
278d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            // TODO: Need to revisit this logic with bigram suggestions
279913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka            final boolean isSuggested = (pos != 0);
280d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka
281d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            final int color;
282913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka            if (index == mCenterSuggestionIndex && willAutoCorrect(suggestions)) {
283d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka                color = mColorAutoCorrect;
284913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka            } else if (isSuggested) {
285913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka                color = mColorSuggested;
286d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            } else {
287d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka                color = mColorTypedWord;
288d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            }
28960a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka
29060a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            final SuggestedWordInfo info = (pos < suggestions.size())
29160a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                    ? suggestions.getInfo(pos) : null;
292add3e053797d7d2355c61160ab746f7dfeb92aefsatok            if (info != null && info.isObsoleteSuggestedWord()) {
293d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka                return applyAlpha(color, 0.5f);
294d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            } else {
295d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka                return color;
296d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            }
297d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        }
298d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka
299d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        private static int applyAlpha(final int color, final float alpha) {
300d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            final int newAlpha = (int)(Color.alpha(color) * alpha);
301d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            return Color.argb(newAlpha, Color.red(color), Color.green(color), Color.blue(color));
302d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        }
303d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka
304d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        public CharSequence getInvertedText(CharSequence text) {
305d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka            if ((mSuggestionStripOption & AUTO_CORRECT_INVERT) == 0)
306d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka                return null;
307d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            final int len = text.length();
308d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            final Spannable word = new SpannableString(text);
309d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            word.setSpan(mInvertedBackgroundColorSpan, 0, len, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
310d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            word.setSpan(mInvertedForegroundColorSpan, 0, len, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
311d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            return word;
312d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        }
313d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka
3143a566c48b0eb3625788e1cce3fb2f58d8f4b380dTadashi G. Takaoka        public void layout(SuggestedWords suggestions, ViewGroup stripView, ViewGroup placer,
31516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                int stripWidth) {
31660a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            if (suggestions.isPunctuationSuggestions()) {
3173a566c48b0eb3625788e1cce3fb2f58d8f4b380dTadashi G. Takaoka                layoutPunctuationSuggestions(suggestions, stripView);
3183a566c48b0eb3625788e1cce3fb2f58d8f4b380dTadashi G. Takaoka                return;
31960a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            }
32060a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka
321913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka            final int countInStrip = mSuggestionsCountInStrip;
32260a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            setupTexts(suggestions, countInStrip);
323bbf25cf25169f640a361370cde5521ffc7789a1bKen Wakasa            mMoreSuggestionsAvailable = (suggestions.size() > countInStrip);
32460a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            int x = 0;
32560a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            for (int index = 0; index < countInStrip; index++) {
32660a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                final int pos = getWordPosition(index, suggestions);
32760a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka
32860a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                if (index != 0) {
32960a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                    final View divider = mDividers.get(pos);
330913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka                    // Add divider if this isn't the left most suggestion in suggestions strip.
33160a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                    stripView.addView(divider);
332013ba3e3e785980b74db83ac5ab1e11b438485daTadashi G. Takaoka                    x += divider.getMeasuredWidth();
33360a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                }
33460a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka
33516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                final CharSequence styled = mTexts.get(pos);
33660a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                final TextView word = mWords.get(pos);
337913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka                if (index == mCenterSuggestionIndex && mMoreSuggestionsAvailable) {
338ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka                    // TODO: This "more suggestions hint" should have nicely designed icon.
339ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka                    word.setCompoundDrawablesWithIntrinsicBounds(
340913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka                            null, null, null, mMoreSuggestionsHint);
341580e1d7ac0cb90a464a3b3aed88047f85a4ab41fTadashi G. Takaoka                    // HACK: To align with other TextView that has no compound drawables.
342913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka                    word.setCompoundDrawablePadding(-mMoreSuggestionsHint.getIntrinsicHeight());
343ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka                } else {
344580e1d7ac0cb90a464a3b3aed88047f85a4ab41fTadashi G. Takaoka                    word.setCompoundDrawablesWithIntrinsicBounds(null, null, null, null);
345ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka                }
346ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka
347913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka                // Disable this suggestion if the suggestion is null or empty.
34860a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                word.setEnabled(!TextUtils.isEmpty(styled));
349913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka                word.setTextColor(getSuggestionTextColor(index, suggestions, pos));
350913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka                final int width = getSuggestionWidth(index, stripWidth);
35160a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                final CharSequence text = getEllipsizedText(styled, width, word.getPaint());
35260a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                final float scaleX = word.getTextScaleX();
35360a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                word.setText(text); // TextView.setText() resets text scale x to 1.0.
35460a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                word.setTextScaleX(scaleX);
35560a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                stripView.addView(word);
356b8dc67466339dc14653ad634c86851025373326bTadashi G. Takaoka                setLayoutWeight(
357913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka                        word, getSuggestionWeight(index), ViewGroup.LayoutParams.MATCH_PARENT);
358013ba3e3e785980b74db83ac5ab1e11b438485daTadashi G. Takaoka                x += word.getMeasuredWidth();
35916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka
36016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                if (DBG) {
36160a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                    final CharSequence debugInfo = getDebugInfo(suggestions, pos);
36216713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    if (debugInfo != null) {
36360a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                        final TextView info = mInfos.get(pos);
36416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                        info.setText(debugInfo);
365013ba3e3e785980b74db83ac5ab1e11b438485daTadashi G. Takaoka                        placer.addView(info);
366b8dc67466339dc14653ad634c86851025373326bTadashi G. Takaoka                        info.measure(ViewGroup.LayoutParams.WRAP_CONTENT,
367b8dc67466339dc14653ad634c86851025373326bTadashi G. Takaoka                                ViewGroup.LayoutParams.WRAP_CONTENT);
36860a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                        final int infoWidth = info.getMeasuredWidth();
36916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                        final int y = info.getMeasuredHeight();
370013ba3e3e785980b74db83ac5ab1e11b438485daTadashi G. Takaoka                        FrameLayoutCompatUtils.placeViewAt(
371013ba3e3e785980b74db83ac5ab1e11b438485daTadashi G. Takaoka                                info, x - infoWidth, y, infoWidth, info.getMeasuredHeight());
37216713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    }
37360a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                }
37416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka            }
37516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka        }
37616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka
377913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka        private int getSuggestionWidth(int index, int maxWidth) {
378913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka            final int paddings = mPadding * mSuggestionsCountInStrip;
379913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka            final int dividers = mDividerWidth * (mSuggestionsCountInStrip - 1);
38060a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            final int availableWidth = maxWidth - paddings - dividers;
381913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka            return (int)(availableWidth * getSuggestionWeight(index));
38260a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka        }
38374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
384913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka        private float getSuggestionWeight(int index) {
385913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka            if (index == mCenterSuggestionIndex) {
386913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka                return mCenterSuggestionWeight;
38760a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            } else {
38860a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                // TODO: Revisit this for cases of 5 or more suggestions
389913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka                return (1.0f - mCenterSuggestionWeight) / (mSuggestionsCountInStrip - 1);
39074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            }
39174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        }
39274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
39360a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka        private void setupTexts(SuggestedWords suggestions, int countInStrip) {
39474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            mTexts.clear();
39560a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            final int count = Math.min(suggestions.size(), countInStrip);
39660a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            for (int pos = 0; pos < count; pos++) {
397913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka                final CharSequence styled = getStyledSuggestionWord(suggestions, pos);
39874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                mTexts.add(styled);
39974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            }
40060a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            for (int pos = count; pos < countInStrip; pos++) {
40160a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                // Make this inactive for touches in layout().
40260a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                mTexts.add(null);
40360a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            }
40474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        }
40574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
4063a566c48b0eb3625788e1cce3fb2f58d8f4b380dTadashi G. Takaoka        private void layoutPunctuationSuggestions(SuggestedWords suggestions, ViewGroup stripView) {
40760a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            final int countInStrip = Math.min(suggestions.size(), PUNCTUATIONS_IN_STRIP);
40860a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            for (int index = 0; index < countInStrip; index++) {
40960a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                if (index != 0) {
410913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka                    // Add divider if this isn't the left most suggestion in suggestions strip.
41160a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                    stripView.addView(mDividers.get(index));
41260a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                }
41360a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka
41460a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                final TextView word = mWords.get(index);
41560a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                word.setEnabled(true);
41660a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                word.setTextColor(mColorTypedWord);
41760a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                final CharSequence text = suggestions.getWord(index);
41860a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                word.setText(text);
41960a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                word.setTextScaleX(1.0f);
420ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka                word.setCompoundDrawables(null, null, null, null);
42160a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                stripView.addView(word);
422913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka                setLayoutWeight(word, 1.0f, mSuggestionsStripHeight);
42360a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            }
424ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka            mMoreSuggestionsAvailable = false;
42574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        }
426c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka
427c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka        public void layoutAddToDictionaryHint(CharSequence word, ViewGroup stripView,
428c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka                int stripWidth) {
429c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            final int width = stripWidth - mDividerWidth - mPadding * 2;
430c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka
431c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            final TextView wordView = mWordToSaveView;
432c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            wordView.setTextColor(mColorTypedWord);
433913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka            final int wordWidth = (int)(width * mCenterSuggestionWeight);
434c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            final CharSequence text = getEllipsizedText(word, wordWidth, wordView.getPaint());
435c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            final float wordScaleX = wordView.getTextScaleX();
436c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            wordView.setTag(word);
437c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            wordView.setText(text);
438c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            wordView.setTextScaleX(wordScaleX);
439c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            stripView.addView(wordView);
440913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka            setLayoutWeight(wordView, mCenterSuggestionWeight, ViewGroup.LayoutParams.MATCH_PARENT);
441c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka
442c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            stripView.addView(mDividers.get(0));
443c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka
444c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            final TextView hintView = mHintToSaveView;
445c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            hintView.setTextColor(mColorAutoCorrect);
446c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            final int hintWidth = width - wordWidth;
447c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            final float hintScaleX = getTextScaleX(mHintToSaveText, hintWidth, hintView.getPaint());
448c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            hintView.setText(mHintToSaveText);
449c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            hintView.setTextScaleX(hintScaleX);
450c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            stripView.addView(hintView);
451b8dc67466339dc14653ad634c86851025373326bTadashi G. Takaoka            setLayoutWeight(
452913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka                    hintView, 1.0f - mCenterSuggestionWeight, ViewGroup.LayoutParams.MATCH_PARENT);
453c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka        }
45474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka    }
45574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
456923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    /**
457913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka     * Construct a {@link SuggestionsView} for showing suggested words for completion.
458923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     * @param context
459923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     * @param attrs
460923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     */
461913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka    public SuggestionsView(Context context, AttributeSet attrs) {
462913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka        this(context, attrs, R.attr.suggestionsViewStyle);
46308a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka    }
46408a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka
465913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka    public SuggestionsView(Context context, AttributeSet attrs, int defStyle) {
466c412309b7a32308b1b0a175dafc13f90254353c5Tadashi G. Takaoka        super(context, attrs, defStyle);
467923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
46816713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka        final LayoutInflater inflater = LayoutInflater.from(context);
469913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka        inflater.inflate(R.layout.suggestions_strip, this);
47086e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka
47186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        mPreviewPopup = new PopupWindow(context);
472913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka        mPreviewText = (TextView) inflater.inflate(R.layout.suggestion_preview, null);
473b8dc67466339dc14653ad634c86851025373326bTadashi G. Takaoka        mPreviewPopup.setWindowLayoutMode(
474b8dc67466339dc14653ad634c86851025373326bTadashi G. Takaoka                ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
475923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mPreviewPopup.setContentView(mPreviewText);
476923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mPreviewPopup.setBackgroundDrawable(null);
477923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
478913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka        mSuggestionsStrip = (ViewGroup)findViewById(R.id.suggestions_strip);
47960a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka        for (int pos = 0; pos < MAX_SUGGESTIONS; pos++) {
480913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka            final TextView word = (TextView)inflater.inflate(R.layout.suggestion_word, null);
48160a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            word.setTag(pos);
4822442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka            word.setOnClickListener(this);
483ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka            word.setOnLongClickListener(this);
4842442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka            mWords.add(word);
485913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka            final View divider = inflater.inflate(R.layout.suggestion_divider, null);
48660a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            divider.setTag(pos);
487a1aab83a24e74cb0fad4b1c1e59b18d23ecbdad3Tadashi G. Takaoka            divider.setOnClickListener(this);
488a1aab83a24e74cb0fad4b1c1e59b18d23ecbdad3Tadashi G. Takaoka            mDividers.add(divider);
489913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka            mInfos.add((TextView)inflater.inflate(R.layout.suggestion_info, null));
490c9716b28ce438e06b5cacc07fc002944bcbe24a0Tadashi G. Takaoka        }
491179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaoka
492d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka        mParams = new SuggestionsViewParams(context, attrs, defStyle, mWords, mDividers, mInfos);
493d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka        mParams.mWordToSaveView.setOnClickListener(this);
49429e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka
49529e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka        mMoreSuggestionsContainer = inflater.inflate(R.layout.more_suggestions, null);
49629e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka        mMoreSuggestionsView = (MoreSuggestionsView)mMoreSuggestionsContainer
49729e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka                .findViewById(R.id.more_suggestions_view);
49829e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka        mMoreSuggestionsBuilder = new MoreSuggestions.Builder(mMoreSuggestionsView);
49929e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka        mMoreSuggestionsWindow = new PopupWindow(context);
50029e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka        mMoreSuggestionsWindow.setWindowLayoutMode(
50129e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka                ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
50229e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka        mMoreSuggestionsWindow.setBackgroundDrawable(null);
503923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
504c9716b28ce438e06b5cacc07fc002944bcbe24a0Tadashi G. Takaoka
505923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    /**
506c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka     * A connection back to the input method.
507923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     * @param listener
508923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     */
50986e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka    public void setListener(Listener listener, View inputView) {
510c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka        mListener = listener;
5111b087064c07975c5e2b9c17d4ca80c56e01c35c0Tadashi G. Takaoka        mKeyboardView = (KeyboardView)inputView.findViewById(R.id.keyboard_view);
512923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
513923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
5147e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka    public void setSuggestions(SuggestedWords suggestions) {
5159fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if (suggestions == null)
516a15e45ef45931ba46678b39c159518d8aa2d4d65Tadashi G. Takaoka            return;
5179fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        mSuggestions = suggestions;
51855b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        if (mShowingAutoCorrectionInverted) {
5199fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            mHandler.postUpdateSuggestions();
52055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        } else {
5219fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            updateSuggestions();
52255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        }
52355b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka    }
52455b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka
5259fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka    private void updateSuggestions() {
526e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        clear();
52716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka        if (mSuggestions.size() == 0)
52874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            return;
52974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
530c412309b7a32308b1b0a175dafc13f90254353c5Tadashi G. Takaoka        mParams.layout(mSuggestions, mSuggestionsStrip, this, getWidth());
53116713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka    }
53274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
53316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka    private static CharSequence getDebugInfo(SuggestedWords suggestions, int pos) {
53460a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka        if (DBG && pos < suggestions.size()) {
53516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka            final SuggestedWordInfo wordInfo = suggestions.getInfo(pos);
53616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka            if (wordInfo != null) {
53716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                final CharSequence debugInfo = wordInfo.getDebugString();
53816713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                if (!TextUtils.isEmpty(debugInfo)) {
53916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    return debugInfo;
540d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka                }
5412442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka            }
54286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        }
54316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka        return null;
54486e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka    }
54586e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka
5463118277dd47492089761c0ed1097abaeb376395cTadashi G. Takaoka    private static void setLayoutWeight(View v, float weight, int height) {
54774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        final ViewGroup.LayoutParams lp = v.getLayoutParams();
54874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        if (lp instanceof LinearLayout.LayoutParams) {
54974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            final LinearLayout.LayoutParams llp = (LinearLayout.LayoutParams)lp;
55074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            llp.weight = weight;
55174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            llp.width = 0;
5523118277dd47492089761c0ed1097abaeb376395cTadashi G. Takaoka            llp.height = height;
55374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        }
55474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka    }
55574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
556c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka    private static float getTextScaleX(CharSequence text, int maxWidth, TextPaint paint) {
557c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka        paint.setTextScaleX(1.0f);
558c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka        final int width = getTextWidth(text, paint);
559c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka        if (width <= maxWidth) {
560c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            return 1.0f;
561c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka        }
562c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka        return maxWidth / (float)width;
563c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka    }
564c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka
56574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka    private static CharSequence getEllipsizedText(CharSequence text, int maxWidth,
56674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            TextPaint paint) {
5675cb10f78ed5c0e17798ea5300d8291b613c5e2a9Tadashi G. Takaoka        if (text == null) return null;
56874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        paint.setTextScaleX(1.0f);
56974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        final int width = getTextWidth(text, paint);
57060a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka        if (width <= maxWidth) {
57160a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            return text;
57260a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka        }
57360a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka        final float scaleX = maxWidth / (float)width;
574b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka        if (scaleX >= MIN_TEXT_XSCALE) {
57574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            paint.setTextScaleX(scaleX);
57674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            return text;
577b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka        }
578b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka
57974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        // Note that TextUtils.ellipsize() use text-x-scale as 1.0 if ellipsize is needed. To get
58060a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka        // squeezed and ellipsized text, passes enlarged width (maxWidth / MIN_TEXT_XSCALE).
58174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        final CharSequence ellipsized = TextUtils.ellipsize(
58274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                text, paint, maxWidth / MIN_TEXT_XSCALE, TextUtils.TruncateAt.MIDDLE);
58374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        paint.setTextScaleX(MIN_TEXT_XSCALE);
58474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        return ellipsized;
585b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka    }
586b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka
58774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka    private static int getTextWidth(CharSequence text, TextPaint paint) {
588b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka        if (TextUtils.isEmpty(text)) return 0;
589fe9b65afa84530d17dd82c770c19de763a50cb58Tadashi G. Takaoka        final Typeface savedTypeface = paint.getTypeface();
59074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        paint.setTypeface(getTextTypeface(text));
591b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka        final int len = text.length();
592b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka        final float[] widths = new float[len];
593b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka        final int count = paint.getTextWidths(text, 0, len, widths);
594fe9b65afa84530d17dd82c770c19de763a50cb58Tadashi G. Takaoka        int width = 0;
595b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka        for (int i = 0; i < count; i++) {
596fe9b65afa84530d17dd82c770c19de763a50cb58Tadashi G. Takaoka            width += Math.round(widths[i] + 0.5f);
597b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka        }
598fe9b65afa84530d17dd82c770c19de763a50cb58Tadashi G. Takaoka        paint.setTypeface(savedTypeface);
599fe9b65afa84530d17dd82c770c19de763a50cb58Tadashi G. Takaoka        return width;
600b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka    }
601b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka
60274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka    private static Typeface getTextTypeface(CharSequence text) {
60374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        if (!(text instanceof SpannableString))
60474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            return Typeface.DEFAULT;
60574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
60674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        final SpannableString ss = (SpannableString)text;
60774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        final StyleSpan[] styles = ss.getSpans(0, text.length(), StyleSpan.class);
60874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        if (styles.length == 0)
60974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            return Typeface.DEFAULT;
61074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
61174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        switch (styles[0].getStyle()) {
61274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        case Typeface.BOLD: return Typeface.DEFAULT_BOLD;
61374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        // TODO: BOLD_ITALIC, ITALIC case?
61474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        default: return Typeface.DEFAULT;
615b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka        }
616b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka    }
617b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka
61855b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka    public void onAutoCorrectionInverted(CharSequence autoCorrectedWord) {
619d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka        final CharSequence inverted = mParams.getInvertedText(autoCorrectedWord);
620d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        if (inverted == null)
62155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            return;
6221e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka        final TextView tv = mWords.get(1);
623d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        tv.setText(inverted);
62455b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        mShowingAutoCorrectionInverted = true;
62555b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka    }
62655b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka
627b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani    public boolean isShowingAddToDictionaryHint() {
628913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka        return mSuggestionsStrip.getChildCount() > 0
629d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka                && mSuggestionsStrip.getChildAt(0) == mParams.mWordToSaveView;
630b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani    }
631b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani
63266a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani    public void showAddToDictionaryHint(CharSequence word) {
633c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka        clear();
634d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka        mParams.layoutAddToDictionaryHint(word, mSuggestionsStrip, getWidth());
63566a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani    }
63666a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani
6376558253160e2039c87f424bd814f402ecd31de3bKen Wakasa    public boolean dismissAddToDictionaryHint() {
638c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka        if (isShowingAddToDictionaryHint()) {
639c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            clear();
640c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            return true;
641c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka        }
642c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka        return false;
6436558253160e2039c87f424bd814f402ecd31de3bKen Wakasa    }
6446558253160e2039c87f424bd814f402ecd31de3bKen Wakasa
6457e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka    public SuggestedWords getSuggestions() {
646979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        return mSuggestions;
647979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
648979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
649923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void clear() {
65055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        mShowingAutoCorrectionInverted = false;
651913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka        mSuggestionsStrip.removeAllViews();
652c412309b7a32308b1b0a175dafc13f90254353c5Tadashi G. Takaoka        removeAllViews();
653c412309b7a32308b1b0a175dafc13f90254353c5Tadashi G. Takaoka        addView(mSuggestionsStrip);
6541b087064c07975c5e2b9c17d4ca80c56e01c35c0Tadashi G. Takaoka        dismissMoreSuggestions();
655923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
656923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
6576ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani    private void hidePreview() {
658179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaoka        mPreviewPopup.dismiss();
6596ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani    }
660e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka
661c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka    private void showPreview(View view, CharSequence word) {
662e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        if (TextUtils.isEmpty(word))
663e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka            return;
664e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka
665e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        final TextView previewText = mPreviewText;
666d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka        previewText.setTextColor(mParams.mColorTypedWord);
667e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        previewText.setText(word);
668b8dc67466339dc14653ad634c86851025373326bTadashi G. Takaoka        previewText.measure(
669b8dc67466339dc14653ad634c86851025373326bTadashi G. Takaoka                ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
670e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        final int[] offsetInWindow = new int[2];
671c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka        view.getLocationInWindow(offsetInWindow);
672e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        final int posX = offsetInWindow[0];
673e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        final int posY = offsetInWindow[1] - previewText.getMeasuredHeight();
674e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        final PopupWindow previewPopup = mPreviewPopup;
675e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        if (previewPopup.isShowing()) {
676e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka            previewPopup.update(posX, posY, previewPopup.getWidth(), previewPopup.getHeight());
677e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        } else {
678e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka            previewPopup.showAtLocation(this, Gravity.NO_GRAVITY, posX, posY);
679923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
680e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        previewText.setVisibility(VISIBLE);
68155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        mHandler.postHidePreview();
682923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
683fcba53ef7c874a4685c12c01404c91b779cae1e8Tadashi G. Takaoka
684e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka    private void addToDictionary(CharSequence word) {
685c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka        if (mListener.addWordToDictionary(word.toString())) {
686c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            final CharSequence message = getContext().getString(R.string.added_word, word);
687d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka            showPreview(mParams.mWordToSaveView, message);
688e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        }
689e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka    }
690e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka
69129e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka    private final KeyboardActionListener mMoreSuggestionsListener =
69229e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka            new KeyboardActionListener.Adapter() {
69329e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka        @Override
69429e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka        public boolean onCustomRequest(int requestCode) {
69529e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka            final int index = requestCode;
69629e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka            final CharSequence word = mSuggestions.getWord(index);
69729e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka            mListener.pickSuggestionManually(index, word);
6981b087064c07975c5e2b9c17d4ca80c56e01c35c0Tadashi G. Takaoka            dismissMoreSuggestions();
69929e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka            return true;
70029e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka        }
70129e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka
70229e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka        @Override
70329e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka        public void onCancelInput() {
7041b087064c07975c5e2b9c17d4ca80c56e01c35c0Tadashi G. Takaoka            dismissMoreSuggestions();
70529e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka        }
70629e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka    };
70729e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka
70829e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka    private final MoreKeysPanel.Controller mMoreSuggestionsController =
70929e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka            new MoreKeysPanel.Controller() {
71029e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka        @Override
71129e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka        public boolean dismissMoreKeysPanel() {
7121b087064c07975c5e2b9c17d4ca80c56e01c35c0Tadashi G. Takaoka            return dismissMoreSuggestions();
71329e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka        }
71429e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka    };
71529e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka
7161b087064c07975c5e2b9c17d4ca80c56e01c35c0Tadashi G. Takaoka    private boolean dismissMoreSuggestions() {
7171b087064c07975c5e2b9c17d4ca80c56e01c35c0Tadashi G. Takaoka        if (mMoreSuggestionsWindow.isShowing()) {
7181b087064c07975c5e2b9c17d4ca80c56e01c35c0Tadashi G. Takaoka            mMoreSuggestionsWindow.dismiss();
7191b087064c07975c5e2b9c17d4ca80c56e01c35c0Tadashi G. Takaoka            mKeyboardView.dimEntireKeyboard(false);
7201b087064c07975c5e2b9c17d4ca80c56e01c35c0Tadashi G. Takaoka            return true;
7211b087064c07975c5e2b9c17d4ca80c56e01c35c0Tadashi G. Takaoka        }
7221b087064c07975c5e2b9c17d4ca80c56e01c35c0Tadashi G. Takaoka        return false;
7231b087064c07975c5e2b9c17d4ca80c56e01c35c0Tadashi G. Takaoka    }
7241b087064c07975c5e2b9c17d4ca80c56e01c35c0Tadashi G. Takaoka
725e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka    @Override
726ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka    public boolean onLongClick(View view) {
727d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka        final SuggestionsViewParams params = mParams;
72829e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka        if (params.mMoreSuggestionsAvailable) {
72929e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka            final int stripWidth = getWidth();
73029e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka            final View container = mMoreSuggestionsContainer;
73129e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka            final int maxWidth = stripWidth - container.getPaddingLeft()
73229e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka                    - container.getPaddingRight();
73329e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka            final MoreSuggestions.Builder builder = mMoreSuggestionsBuilder;
7349676038b6e9fb66760588d7f9c9c642cc493dd71Tadashi G. Takaoka            builder.layout(mSuggestions, params.mSuggestionsCountInStrip, maxWidth,
7359676038b6e9fb66760588d7f9c9c642cc493dd71Tadashi G. Takaoka                    (int)(maxWidth * params.mMinMoreSuggestionsWidth),
7369676038b6e9fb66760588d7f9c9c642cc493dd71Tadashi G. Takaoka                    params.mMaxMoreSuggestionsRow);
73729e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka            mMoreSuggestionsView.setKeyboard(builder.build());
73829e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka            container.measure(
73929e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka                    ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
74029e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka
74129e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka            final MoreKeysPanel moreKeysPanel = mMoreSuggestionsView;
74229e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka            final int pointX = stripWidth / 2;
74329e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka            final int pointY = 0;
74429e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka            moreKeysPanel.showMoreKeysPanel(
74529e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka                    this, mMoreSuggestionsController, pointX, pointY,
74629e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka                    mMoreSuggestionsWindow, mMoreSuggestionsListener);
74729e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka            // TODO: Should figure out how to select the pointer tracker correctly.
74829e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka            final PointerTracker tracker = PointerTracker.getPointerTracker(0, moreKeysPanel);
74929e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka            final int translatedX = moreKeysPanel.translateX(tracker.getLastX());
75029e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka            final int translatedY = moreKeysPanel.translateY(tracker.getLastY());
75129e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka            tracker.onShowMoreKeysPanel(
75229e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka                    translatedX, translatedY, SystemClock.uptimeMillis(), moreKeysPanel);
75329e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka            view.setPressed(false);
7541b087064c07975c5e2b9c17d4ca80c56e01c35c0Tadashi G. Takaoka            mKeyboardView.dimEntireKeyboard(true);
755ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka            return true;
756ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka        }
757ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka        return false;
758ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka    }
759ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka
760ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka    @Override
76129e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka    public boolean dispatchTouchEvent(MotionEvent me) {
76229e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka        if (!mMoreSuggestionsWindow.isShowing()) {
76329e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka            return super.dispatchTouchEvent(me);
76429e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka        }
7658ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka
7668ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka        final MoreKeysPanel moreKeysPanel = mMoreSuggestionsView;
76729e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka        final int action = me.getAction();
76829e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka        final long eventTime = me.getEventTime();
76929e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka        final int index = me.getActionIndex();
77029e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka        final int id = me.getPointerId(index);
7718ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka        final PointerTracker tracker = PointerTracker.getPointerTracker(id, moreKeysPanel);
7728ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka        final int x = (int)me.getX(index);
7738ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka        final int y = (int)me.getY(index);
7748ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka        final int translatedX = moreKeysPanel.translateX(x);
7758ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka        final int translatedY = moreKeysPanel.translateY(y);
7768ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka
7778ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka        tracker.processMotionEvent(action, translatedX, translatedY, eventTime, moreKeysPanel);
77829e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka        return true;
77929e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka    }
78029e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka
78129e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka    @Override
782e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka    public void onClick(View view) {
783d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka        if (view == mParams.mWordToSaveView) {
784c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            addToDictionary((CharSequence)view.getTag());
785717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka            clear();
786717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka            return;
787717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka        }
788717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka
78986e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        final Object tag = view.getTag();
79086e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        if (!(tag instanceof Integer))
79186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka            return;
79286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        final int index = (Integer) tag;
79337deb112c727dfed5e94d054cf5f00f5d60c8120Tadashi G. Takaoka        if (index >= mSuggestions.size())
79437deb112c727dfed5e94d054cf5f00f5d60c8120Tadashi G. Takaoka            return;
79586e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka
79637deb112c727dfed5e94d054cf5f00f5d60c8120Tadashi G. Takaoka        final CharSequence word = mSuggestions.getWord(index);
797717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka        mListener.pickSuggestionManually(index, word);
798923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
79982411d47ba7e8133ed2390c6920945e139a738cesatok
8006ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani    @Override
8016ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani    public void onDetachedFromWindow() {
8026ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani        super.onDetachedFromWindow();
80355b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        mHandler.cancelAllMessages();
8046ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani        hidePreview();
8056ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani    }
806923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project}
807