SuggestionStripView.java revision a729377395967f7652d93992cbcf50cd2ff522d1
1923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project/*
2913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka * Copyright (C) 2011 The Android Open Source Project
3e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka *
48aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * Licensed under the Apache License, Version 2.0 (the "License");
58aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * you may not use this file except in compliance with the License.
68aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * You may obtain a copy of the License at
7e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka *
88aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka *      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
118aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * distributed under the License is distributed on an "AS IS" BASIS,
128aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
138aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * See the License for the specific language governing permissions and
148aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * limitations under the License.
15923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */
16923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
178c3d5b6961a9b9d40c4bf21ad495f852971c24f4Tadashi G. Takaokapackage com.android.inputmethod.latin.suggestions;
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;
220967ef40368c4bc7a0576ecc3dc222a8fe9b94c3Tadashi G. Takaokaimport android.graphics.Bitmap;
230967ef40368c4bc7a0576ecc3dc222a8fe9b94c3Tadashi G. Takaokaimport android.graphics.Canvas;
246f7218627eda110a8454053f8ecb7b80edfdc8cesatokimport android.graphics.Color;
250967ef40368c4bc7a0576ecc3dc222a8fe9b94c3Tadashi G. Takaokaimport android.graphics.Paint;
260967ef40368c4bc7a0576ecc3dc222a8fe9b94c3Tadashi G. Takaokaimport android.graphics.Paint.Align;
270967ef40368c4bc7a0576ecc3dc222a8fe9b94c3Tadashi G. Takaokaimport android.graphics.Rect;
28923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.graphics.Typeface;
290967ef40368c4bc7a0576ecc3dc222a8fe9b94c3Tadashi G. Takaokaimport android.graphics.drawable.BitmapDrawable;
30e583371b13ebd9aa336d0883e8c174ae4918c758Tadashi G. Takaokaimport android.graphics.drawable.Drawable;
31522d5c16d20657e7d26009fe9c067404e16a6c2aTadashi G. Takaokaimport android.text.Spannable;
32522d5c16d20657e7d26009fe9c067404e16a6c2aTadashi G. Takaokaimport android.text.SpannableString;
33e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaokaimport android.text.Spanned;
34b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaokaimport android.text.TextPaint;
35e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaokaimport android.text.TextUtils;
36522d5c16d20657e7d26009fe9c067404e16a6c2aTadashi G. Takaokaimport android.text.style.CharacterStyle;
3774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaokaimport android.text.style.StyleSpan;
38522d5c16d20657e7d26009fe9c067404e16a6c2aTadashi G. Takaokaimport android.text.style.UnderlineSpan;
39923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.util.AttributeSet;
403fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaokaimport android.view.GestureDetector;
41923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.Gravity;
42923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.LayoutInflater;
4329e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaokaimport android.view.MotionEvent;
44923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.View;
45e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaokaimport android.view.View.OnClickListener;
46ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaokaimport android.view.View.OnLongClickListener;
47e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaokaimport android.view.ViewGroup;
48e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaokaimport android.widget.LinearLayout;
49c412309b7a32308b1b0a175dafc13f90254353c5Tadashi G. Takaokaimport android.widget.RelativeLayout;
50923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.widget.TextView;
51923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
527339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaokaimport com.android.inputmethod.keyboard.Keyboard;
5329e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaokaimport com.android.inputmethod.keyboard.KeyboardActionListener;
547339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaokaimport com.android.inputmethod.keyboard.KeyboardSwitcher;
55d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaokaimport com.android.inputmethod.keyboard.MainKeyboardView;
5629e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaokaimport com.android.inputmethod.keyboard.MoreKeysPanel;
57c8461d1ae26d43a09c0f835d833f3d49fbe8d2f3Tadashi G. Takaokaimport com.android.inputmethod.keyboard.ViewLayoutUtils;
58f72b8f5662afb42b08eb88e92731d52f99df13e3Jean Chalardimport com.android.inputmethod.latin.AutoCorrection;
595f282ea9e4a4590fcbab6e27d5fca7dacbb40a6aTadashi G. Takaokaimport com.android.inputmethod.latin.CollectionUtils;
605faf41951929301af80026bc3191812ef874fd5aTadashi G. Takaokaimport com.android.inputmethod.latin.Constants;
618c3d5b6961a9b9d40c4bf21ad495f852971c24f4Tadashi G. Takaokaimport com.android.inputmethod.latin.LatinImeLogger;
628c3d5b6961a9b9d40c4bf21ad495f852971c24f4Tadashi G. Takaokaimport com.android.inputmethod.latin.R;
6392821614fd80112527e133f069e31ee48250314fTadashi G. Takaokaimport com.android.inputmethod.latin.ResourceUtils;
648c3d5b6961a9b9d40c4bf21ad495f852971c24f4Tadashi G. Takaokaimport com.android.inputmethod.latin.SuggestedWords;
65042557b45bf2554608cd22874633011157cd1752Jean Chalardimport com.android.inputmethod.latin.Utils;
66a9ca7867b5a7c0be115966211a05f5d460c8638cKurt Partridgeimport com.android.inputmethod.latin.define.ProductionFlag;
676b966160ac8570271547bf63217efa5e228d4accKurt Partridgeimport com.android.inputmethod.research.ResearchLogger;
68ddb61ea461b920d87be4ad78c8a36eec1013b965Tadashi G. Takaoka
69179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaokaimport java.util.ArrayList;
70179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaoka
71a28a05e971cc242b338331a3b78276fa95188d19Tadashi G. Takaokapublic final class SuggestionStripView extends RelativeLayout implements OnClickListener,
72c412309b7a32308b1b0a175dafc13f90254353c5Tadashi G. Takaoka        OnLongClickListener {
73c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka    public interface Listener {
7418d688c94bb8e1e26de2d12445cb3096c6126f75Jean Chalard        public void addWordToUserDictionary(String word);
75bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka        public void pickSuggestionManually(int index, String word);
76c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka    }
77c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka
7886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka    // The maximum number of suggestions available. See {@link Suggest#mPrefMaxSuggestions}.
7929e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka    public static final int MAX_SUGGESTIONS = 18;
80923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
818c3d5b6961a9b9d40c4bf21ad495f852971c24f4Tadashi G. Takaoka    static final boolean DBG = LatinImeLogger.sDBG;
826f7218627eda110a8454053f8ecb7b80edfdc8cesatok
83913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka    private final ViewGroup mSuggestionsStrip;
84d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka    MainKeyboardView mMainKeyboardView;
8574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
8629e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka    private final View mMoreSuggestionsContainer;
8729e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka    private final MoreSuggestionsView mMoreSuggestionsView;
8829e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka    private final MoreSuggestions.Builder mMoreSuggestionsBuilder;
8929e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka
905f282ea9e4a4590fcbab6e27d5fca7dacbb40a6aTadashi G. Takaoka    private final ArrayList<TextView> mWords = CollectionUtils.newArrayList();
915f282ea9e4a4590fcbab6e27d5fca7dacbb40a6aTadashi G. Takaoka    private final ArrayList<TextView> mInfos = CollectionUtils.newArrayList();
925f282ea9e4a4590fcbab6e27d5fca7dacbb40a6aTadashi G. Takaoka    private final ArrayList<View> mDividers = CollectionUtils.newArrayList();
9374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
943e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka    Listener mListener;
953e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka    SuggestedWords mSuggestedWords = SuggestedWords.EMPTY;
966a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani
974702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka    private final SuggestionStripViewParams mParams;
98ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka    private static final float MIN_TEXT_XSCALE = 0.70f;
99b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka
100a28a05e971cc242b338331a3b78276fa95188d19Tadashi G. Takaoka    private static final class SuggestionStripViewParams {
101d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka        private static final int DEFAULT_SUGGESTIONS_COUNT_IN_STRIP = 3;
102ef2bfad5903fb55adca61dbea51984fbc7e4375fTadashi G. Takaoka        private static final float DEFAULT_CENTER_SUGGESTION_PERCENTILE = 0.40f;
1039676038b6e9fb66760588d7f9c9c642cc493dd71Tadashi G. Takaoka        private static final int DEFAULT_MAX_MORE_SUGGESTIONS_ROW = 2;
104293db0873fd89b5c2bd077ffa5091321b3ab8149Ken Wakasa        private static final int PUNCTUATIONS_IN_STRIP = 5;
105d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka
10674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        public final int mPadding;
10774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        public final int mDividerWidth;
108913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka        public final int mSuggestionsStripHeight;
109d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka        public final int mSuggestionsCountInStrip;
110c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka        public final int mMoreSuggestionsRowHeight;
111c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka        private int mMaxMoreSuggestionsRow;
1129676038b6e9fb66760588d7f9c9c642cc493dd71Tadashi G. Takaoka        public final float mMinMoreSuggestionsWidth;
1134269a7cebdfe5c76372d0f0dd187432f0594ffe5Tadashi G. Takaoka        public final int mMoreSuggestionsBottomGap;
11416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka
115660776e09b9a3b321074a94721d901a035ca1b9fKen Wakasa        private final ArrayList<TextView> mWords;
116660776e09b9a3b321074a94721d901a035ca1b9fKen Wakasa        private final ArrayList<View> mDividers;
117660776e09b9a3b321074a94721d901a035ca1b9fKen Wakasa        private final ArrayList<TextView> mInfos;
118d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka
119a44685ab326809185a0e4c44afabe8fd93441b4cTadashi G. Takaoka        private final int mColorValidTypedWord;
120d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        private final int mColorTypedWord;
121d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        private final int mColorAutoCorrect;
122913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka        private final int mColorSuggested;
123697bf585f8dac6ffc4d008c02b63407cfdd83104Tadashi G. Takaoka        private final float mAlphaObsoleted;
124913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka        private final float mCenterSuggestionWeight;
125913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka        private final int mCenterSuggestionIndex;
126913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka        private final Drawable mMoreSuggestionsHint;
1279bdce3a59e9bf00095bc92fae88b830b0a8455beFabrice Di Meglio        private static final String MORE_SUGGESTIONS_HINT = "\u2026";
1282eb8781dc2e42d55474fb6e5c461c56c066b8363Tadashi G. Takaoka        private static final String LEFTWARDS_ARROW = "\u2190";
129d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka
130d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        private static final CharacterStyle BOLD_SPAN = new StyleSpan(Typeface.BOLD);
131d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        private static final CharacterStyle UNDERLINE_SPAN = new UnderlineSpan();
132d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        private static final int AUTO_CORRECT_BOLD = 0x01;
133d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        private static final int AUTO_CORRECT_UNDERLINE = 0x02;
13477a87e3cb5886b1319230906c77c0bc98b905248Tadashi G. Takaoka        private static final int VALID_TYPED_WORD_BOLD = 0x04;
135d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka
136d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka        private final int mSuggestionStripOption;
13774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
1385f282ea9e4a4590fcbab6e27d5fca7dacbb40a6aTadashi G. Takaoka        private final ArrayList<CharSequence> mTexts = CollectionUtils.newArrayList();
13974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
140ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka        public boolean mMoreSuggestionsAvailable;
141ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka
1429f763d14451685965039990891eb0bc8e8db0735Tadashi G. Takaoka        private final TextView mWordToSaveView;
1432eb8781dc2e42d55474fb6e5c461c56c066b8363Tadashi G. Takaoka        private final TextView mLeftwardsArrowView;
144c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka        private final TextView mHintToSaveView;
145c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka
1463e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka        public SuggestionStripViewParams(final Context context, final AttributeSet attrs,
1473e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka                final int defStyle, final ArrayList<TextView> words, final ArrayList<View> dividers,
1483e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka                final ArrayList<TextView> infos) {
149d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka            mWords = words;
150d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka            mDividers = dividers;
151d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka            mInfos = infos;
152d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka
153d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka            final TextView word = words.get(0);
154d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka            final View divider = dividers.get(0);
155d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka            mPadding = word.getCompoundPaddingLeft() + word.getCompoundPaddingRight();
156d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka            divider.measure(
157d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka                    ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
158d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka            mDividerWidth = divider.getMeasuredWidth();
159d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka
160d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka            final Resources res = word.getResources();
161d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka            mSuggestionsStripHeight = res.getDimensionPixelSize(R.dimen.suggestions_strip_height);
162d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka
1634702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka            final TypedArray a = context.obtainStyledAttributes(attrs,
1644702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka                    R.styleable.SuggestionStripView, defStyle, R.style.SuggestionStripViewStyle);
1654702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka            mSuggestionStripOption = a.getInt(
1664702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka                    R.styleable.SuggestionStripView_suggestionStripOption, 0);
16792821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka            final float alphaValidTypedWord = ResourceUtils.getFraction(a,
168ef2bfad5903fb55adca61dbea51984fbc7e4375fTadashi G. Takaoka                    R.styleable.SuggestionStripView_alphaValidTypedWord, 1.0f);
16992821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka            final float alphaTypedWord = ResourceUtils.getFraction(a,
170ef2bfad5903fb55adca61dbea51984fbc7e4375fTadashi G. Takaoka                    R.styleable.SuggestionStripView_alphaTypedWord, 1.0f);
17192821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka            final float alphaAutoCorrect = ResourceUtils.getFraction(a,
172ef2bfad5903fb55adca61dbea51984fbc7e4375fTadashi G. Takaoka                    R.styleable.SuggestionStripView_alphaAutoCorrect, 1.0f);
17392821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka            final float alphaSuggested = ResourceUtils.getFraction(a,
174ef2bfad5903fb55adca61dbea51984fbc7e4375fTadashi G. Takaoka                    R.styleable.SuggestionStripView_alphaSuggested, 1.0f);
17592821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka            mAlphaObsoleted = ResourceUtils.getFraction(a,
176ef2bfad5903fb55adca61dbea51984fbc7e4375fTadashi G. Takaoka                    R.styleable.SuggestionStripView_alphaSuggested, 1.0f);
1774702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka            mColorValidTypedWord = applyAlpha(a.getColor(
1784702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka                    R.styleable.SuggestionStripView_colorValidTypedWord, 0), alphaValidTypedWord);
1794702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka            mColorTypedWord = applyAlpha(a.getColor(
1804702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka                    R.styleable.SuggestionStripView_colorTypedWord, 0), alphaTypedWord);
1814702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka            mColorAutoCorrect = applyAlpha(a.getColor(
1824702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka                    R.styleable.SuggestionStripView_colorAutoCorrect, 0), alphaAutoCorrect);
1834702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka            mColorSuggested = applyAlpha(a.getColor(
1844702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka                    R.styleable.SuggestionStripView_colorSuggested, 0), alphaSuggested);
185913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka            mSuggestionsCountInStrip = a.getInt(
1864702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka                    R.styleable.SuggestionStripView_suggestionsCountInStrip,
187913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka                    DEFAULT_SUGGESTIONS_COUNT_IN_STRIP);
18892821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka            mCenterSuggestionWeight = ResourceUtils.getFraction(a,
1894702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka                    R.styleable.SuggestionStripView_centerSuggestionPercentile,
190697bf585f8dac6ffc4d008c02b63407cfdd83104Tadashi G. Takaoka                    DEFAULT_CENTER_SUGGESTION_PERCENTILE);
1919676038b6e9fb66760588d7f9c9c642cc493dd71Tadashi G. Takaoka            mMaxMoreSuggestionsRow = a.getInt(
1924702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka                    R.styleable.SuggestionStripView_maxMoreSuggestionsRow,
1939676038b6e9fb66760588d7f9c9c642cc493dd71Tadashi G. Takaoka                    DEFAULT_MAX_MORE_SUGGESTIONS_ROW);
19492821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka            mMinMoreSuggestionsWidth = ResourceUtils.getFraction(a,
195ef2bfad5903fb55adca61dbea51984fbc7e4375fTadashi G. Takaoka                    R.styleable.SuggestionStripView_minMoreSuggestionsWidth, 1.0f);
196d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            a.recycle();
197d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka
1980967ef40368c4bc7a0576ecc3dc222a8fe9b94c3Tadashi G. Takaoka            mMoreSuggestionsHint = getMoreSuggestionsHint(res,
1990967ef40368c4bc7a0576ecc3dc222a8fe9b94c3Tadashi G. Takaoka                    res.getDimension(R.dimen.more_suggestions_hint_text_size), mColorAutoCorrect);
200913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka            mCenterSuggestionIndex = mSuggestionsCountInStrip / 2;
2014269a7cebdfe5c76372d0f0dd187432f0594ffe5Tadashi G. Takaoka            mMoreSuggestionsBottomGap = res.getDimensionPixelOffset(
2024269a7cebdfe5c76372d0f0dd187432f0594ffe5Tadashi G. Takaoka                    R.dimen.more_suggestions_bottom_gap);
203c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka            mMoreSuggestionsRowHeight = res.getDimensionPixelSize(
204c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka                    R.dimen.more_suggestions_row_height);
20560a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka
206c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            final LayoutInflater inflater = LayoutInflater.from(context);
207913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka            mWordToSaveView = (TextView)inflater.inflate(R.layout.suggestion_word, null);
2082eb8781dc2e42d55474fb6e5c461c56c066b8363Tadashi G. Takaoka            mLeftwardsArrowView = (TextView)inflater.inflate(R.layout.hint_add_to_dictionary, null);
2092eb8781dc2e42d55474fb6e5c461c56c066b8363Tadashi G. Takaoka            mHintToSaveView = (TextView)inflater.inflate(R.layout.hint_add_to_dictionary, null);
21074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        }
21174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
212c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka        public int getMaxMoreSuggestionsRow() {
213c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka            return mMaxMoreSuggestionsRow;
214c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka        }
215c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka
216c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka        private int getMoreSuggestionsHeight() {
217c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka            return mMaxMoreSuggestionsRow * mMoreSuggestionsRowHeight + mMoreSuggestionsBottomGap;
218c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka        }
219c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka
2203e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka        public int setMoreSuggestionsHeight(final int remainingHeight) {
221c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka            final int currentHeight = getMoreSuggestionsHeight();
222c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka            if (currentHeight <= remainingHeight) {
223c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka                return currentHeight;
224c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka            }
225c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka
226c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka            mMaxMoreSuggestionsRow = (remainingHeight - mMoreSuggestionsBottomGap)
227c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka                    / mMoreSuggestionsRowHeight;
228c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka            final int newHeight = getMoreSuggestionsHeight();
229c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka            return newHeight;
230c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka        }
231c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka
2323e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka        private static Drawable getMoreSuggestionsHint(final Resources res, final float textSize,
2333e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka                final int color) {
2340967ef40368c4bc7a0576ecc3dc222a8fe9b94c3Tadashi G. Takaoka            final Paint paint = new Paint();
2350967ef40368c4bc7a0576ecc3dc222a8fe9b94c3Tadashi G. Takaoka            paint.setAntiAlias(true);
2360967ef40368c4bc7a0576ecc3dc222a8fe9b94c3Tadashi G. Takaoka            paint.setTextAlign(Align.CENTER);
2370967ef40368c4bc7a0576ecc3dc222a8fe9b94c3Tadashi G. Takaoka            paint.setTextSize(textSize);
2380967ef40368c4bc7a0576ecc3dc222a8fe9b94c3Tadashi G. Takaoka            paint.setColor(color);
2390967ef40368c4bc7a0576ecc3dc222a8fe9b94c3Tadashi G. Takaoka            final Rect bounds = new Rect();
240c9f562a9a4c2b634eb43d1ddaef69068c0d93f6fKen Wakasa            paint.getTextBounds(MORE_SUGGESTIONS_HINT, 0, MORE_SUGGESTIONS_HINT.length(), bounds);
2410967ef40368c4bc7a0576ecc3dc222a8fe9b94c3Tadashi G. Takaoka            final int width = Math.round(bounds.width() + 0.5f);
2420967ef40368c4bc7a0576ecc3dc222a8fe9b94c3Tadashi G. Takaoka            final int height = Math.round(bounds.height() + 0.5f);
2430967ef40368c4bc7a0576ecc3dc222a8fe9b94c3Tadashi G. Takaoka            final Bitmap buffer = Bitmap.createBitmap(
2440967ef40368c4bc7a0576ecc3dc222a8fe9b94c3Tadashi G. Takaoka                    width, (height * 3 / 2), Bitmap.Config.ARGB_8888);
2450967ef40368c4bc7a0576ecc3dc222a8fe9b94c3Tadashi G. Takaoka            final Canvas canvas = new Canvas(buffer);
2460967ef40368c4bc7a0576ecc3dc222a8fe9b94c3Tadashi G. Takaoka            canvas.drawText(MORE_SUGGESTIONS_HINT, width / 2, height, paint);
2470967ef40368c4bc7a0576ecc3dc222a8fe9b94c3Tadashi G. Takaoka            return new BitmapDrawable(res, buffer);
2480967ef40368c4bc7a0576ecc3dc222a8fe9b94c3Tadashi G. Takaoka        }
2490967ef40368c4bc7a0576ecc3dc222a8fe9b94c3Tadashi G. Takaoka
2503e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka        private CharSequence getStyledSuggestionWord(final SuggestedWords suggestedWords,
2513e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka                final int pos) {
252bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka            final String word = suggestedWords.getWord(pos);
253e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka            final boolean isAutoCorrect = pos == 1 && suggestedWords.willAutoCorrect();
254e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka            final boolean isTypedWordValid = pos == 0 && suggestedWords.mTypedWordValid;
255d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka            if (!isAutoCorrect && !isTypedWordValid)
256d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka                return word;
257d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka
258d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            final int len = word.length();
259d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            final Spannable spannedWord = new SpannableString(word);
260d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka            final int option = mSuggestionStripOption;
261d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka            if ((isAutoCorrect && (option & AUTO_CORRECT_BOLD) != 0)
262d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka                    || (isTypedWordValid && (option & VALID_TYPED_WORD_BOLD) != 0)) {
263d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka                spannedWord.setSpan(BOLD_SPAN, 0, len, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
264d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka            }
265d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka            if (isAutoCorrect && (option & AUTO_CORRECT_UNDERLINE) != 0) {
266d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka                spannedWord.setSpan(UNDERLINE_SPAN, 0, len, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
267d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka            }
268d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            return spannedWord;
269d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        }
270d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka
2713e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka        private int getWordPosition(final int index, final SuggestedWords suggestedWords) {
27260a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            // TODO: This works for 3 suggestions. Revisit this algorithm when there are 5 or more
27360a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            // suggestions.
274e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka            final int centerPos = suggestedWords.willAutoCorrect() ? 1 : 0;
275913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka            if (index == mCenterSuggestionIndex) {
27660a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                return centerPos;
27760a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            } else if (index == centerPos) {
278913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka                return mCenterSuggestionIndex;
27960a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            } else {
280d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka                return index;
281d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            }
282d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        }
283d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka
2843e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka        private int getSuggestionTextColor(final int index, final SuggestedWords suggestedWords,
2853e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka                final int pos) {
286d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            // TODO: Need to revisit this logic with bigram suggestions
287913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka            final boolean isSuggested = (pos != 0);
288d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka
289d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            final int color;
290e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka            if (index == mCenterSuggestionIndex && suggestedWords.willAutoCorrect()) {
291d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka                color = mColorAutoCorrect;
292e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka            } else if (index == mCenterSuggestionIndex && suggestedWords.mTypedWordValid) {
293a44685ab326809185a0e4c44afabe8fd93441b4cTadashi G. Takaoka                color = mColorValidTypedWord;
294913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka            } else if (isSuggested) {
295913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka                color = mColorSuggested;
296d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            } else {
297d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka                color = mColorTypedWord;
298d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            }
299c0c20b386fb06b688f56dd7f807e2bcbb70b3a59Jean Chalard            if (LatinImeLogger.sDBG && suggestedWords.size() > 1) {
300ebbb7e9665b2f9bce46ddc2daa82b9ef73f6c712Jean Chalard                // If we auto-correct, then the autocorrection is in slot 0 and the typed word
301ebbb7e9665b2f9bce46ddc2daa82b9ef73f6c712Jean Chalard                // is in slot 1.
302f72b8f5662afb42b08eb88e92731d52f99df13e3Jean Chalard                if (index == mCenterSuggestionIndex
303f72b8f5662afb42b08eb88e92731d52f99df13e3Jean Chalard                        && AutoCorrection.shouldBlockAutoCorrectionBySafetyNet(
304bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka                                suggestedWords.getWord(1), suggestedWords.getWord(0))) {
3052aa1dd45c44295e2f7e8ece1b520032d86b9f908satok                    return 0xFFFF0000;
3062aa1dd45c44295e2f7e8ece1b520032d86b9f908satok                }
3072aa1dd45c44295e2f7e8ece1b520032d86b9f908satok            }
30860a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka
3094f6cf258fe208329247ade7a6701ac9709820717Jean Chalard            if (suggestedWords.mIsObsoleteSuggestions && isSuggested) {
310697bf585f8dac6ffc4d008c02b63407cfdd83104Tadashi G. Takaoka                return applyAlpha(color, mAlphaObsoleted);
311d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            } else {
312d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka                return color;
313d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            }
314d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        }
315d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka
316d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        private static int applyAlpha(final int color, final float alpha) {
317d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            final int newAlpha = (int)(Color.alpha(color) * alpha);
318d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            return Color.argb(newAlpha, Color.red(color), Color.green(color), Color.blue(color));
319d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        }
320d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka
3212c47080e7b4b9b2a6c2dbf1444e041c1b7943316Tadashi G. Takaoka        private static void addDivider(final ViewGroup stripView, final View divider) {
3222c47080e7b4b9b2a6c2dbf1444e041c1b7943316Tadashi G. Takaoka            stripView.addView(divider);
3232c47080e7b4b9b2a6c2dbf1444e041c1b7943316Tadashi G. Takaoka            final LinearLayout.LayoutParams params =
3242c47080e7b4b9b2a6c2dbf1444e041c1b7943316Tadashi G. Takaoka                    (LinearLayout.LayoutParams)divider.getLayoutParams();
3252c47080e7b4b9b2a6c2dbf1444e041c1b7943316Tadashi G. Takaoka            params.gravity = Gravity.CENTER;
3262c47080e7b4b9b2a6c2dbf1444e041c1b7943316Tadashi G. Takaoka        }
3272c47080e7b4b9b2a6c2dbf1444e041c1b7943316Tadashi G. Takaoka
3283e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka        public void layout(final SuggestedWords suggestedWords, final ViewGroup stripView,
3293e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka                final ViewGroup placer, final int stripWidth) {
330e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka            if (suggestedWords.mIsPunctuationSuggestions) {
331e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka                layoutPunctuationSuggestions(suggestedWords, stripView);
3323a566c48b0eb3625788e1cce3fb2f58d8f4b380dTadashi G. Takaoka                return;
33360a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            }
33460a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka
335913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka            final int countInStrip = mSuggestionsCountInStrip;
336e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka            setupTexts(suggestedWords, countInStrip);
337e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka            mMoreSuggestionsAvailable = (suggestedWords.size() > countInStrip);
33860a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            int x = 0;
33960a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            for (int index = 0; index < countInStrip; index++) {
340e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka                final int pos = getWordPosition(index, suggestedWords);
34160a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka
34260a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                if (index != 0) {
34360a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                    final View divider = mDividers.get(pos);
344913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka                    // Add divider if this isn't the left most suggestion in suggestions strip.
3452c47080e7b4b9b2a6c2dbf1444e041c1b7943316Tadashi G. Takaoka                    addDivider(stripView, divider);
346013ba3e3e785980b74db83ac5ab1e11b438485daTadashi G. Takaoka                    x += divider.getMeasuredWidth();
34760a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                }
34860a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka
34916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                final CharSequence styled = mTexts.get(pos);
35060a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                final TextView word = mWords.get(pos);
351913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka                if (index == mCenterSuggestionIndex && mMoreSuggestionsAvailable) {
352ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka                    // TODO: This "more suggestions hint" should have nicely designed icon.
353ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka                    word.setCompoundDrawablesWithIntrinsicBounds(
354913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka                            null, null, null, mMoreSuggestionsHint);
355580e1d7ac0cb90a464a3b3aed88047f85a4ab41fTadashi G. Takaoka                    // HACK: To align with other TextView that has no compound drawables.
356913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka                    word.setCompoundDrawablePadding(-mMoreSuggestionsHint.getIntrinsicHeight());
357ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka                } else {
358580e1d7ac0cb90a464a3b3aed88047f85a4ab41fTadashi G. Takaoka                    word.setCompoundDrawablesWithIntrinsicBounds(null, null, null, null);
359ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka                }
360ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka
361913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka                // Disable this suggestion if the suggestion is null or empty.
36260a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                word.setEnabled(!TextUtils.isEmpty(styled));
363e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka                word.setTextColor(getSuggestionTextColor(index, suggestedWords, pos));
364913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka                final int width = getSuggestionWidth(index, stripWidth);
36560a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                final CharSequence text = getEllipsizedText(styled, width, word.getPaint());
36660a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                final float scaleX = word.getTextScaleX();
36760a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                word.setText(text); // TextView.setText() resets text scale x to 1.0.
36860a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                word.setTextScaleX(scaleX);
36960a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                stripView.addView(word);
370b8dc67466339dc14653ad634c86851025373326bTadashi G. Takaoka                setLayoutWeight(
371913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka                        word, getSuggestionWeight(index), ViewGroup.LayoutParams.MATCH_PARENT);
372013ba3e3e785980b74db83ac5ab1e11b438485daTadashi G. Takaoka                x += word.getMeasuredWidth();
37316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka
374042557b45bf2554608cd22874633011157cd1752Jean Chalard                if (DBG && pos < suggestedWords.size()) {
375bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka                    final String debugInfo = Utils.getDebugInfo(suggestedWords, pos);
37616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    if (debugInfo != null) {
37760a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                        final TextView info = mInfos.get(pos);
37816713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                        info.setText(debugInfo);
379013ba3e3e785980b74db83ac5ab1e11b438485daTadashi G. Takaoka                        placer.addView(info);
380b8dc67466339dc14653ad634c86851025373326bTadashi G. Takaoka                        info.measure(ViewGroup.LayoutParams.WRAP_CONTENT,
381b8dc67466339dc14653ad634c86851025373326bTadashi G. Takaoka                                ViewGroup.LayoutParams.WRAP_CONTENT);
38260a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                        final int infoWidth = info.getMeasuredWidth();
38316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                        final int y = info.getMeasuredHeight();
384c8461d1ae26d43a09c0f835d833f3d49fbe8d2f3Tadashi G. Takaoka                        ViewLayoutUtils.placeViewAt(
385013ba3e3e785980b74db83ac5ab1e11b438485daTadashi G. Takaoka                                info, x - infoWidth, y, infoWidth, info.getMeasuredHeight());
38616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    }
38760a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                }
38816713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka            }
38916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka        }
39016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka
3913e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka        private int getSuggestionWidth(final int index, final int maxWidth) {
392913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka            final int paddings = mPadding * mSuggestionsCountInStrip;
393913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka            final int dividers = mDividerWidth * (mSuggestionsCountInStrip - 1);
39460a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            final int availableWidth = maxWidth - paddings - dividers;
395913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka            return (int)(availableWidth * getSuggestionWeight(index));
39660a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka        }
39774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
3983e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka        private float getSuggestionWeight(final int index) {
399913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka            if (index == mCenterSuggestionIndex) {
400913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka                return mCenterSuggestionWeight;
40160a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            } else {
40260a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                // TODO: Revisit this for cases of 5 or more suggestions
403913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka                return (1.0f - mCenterSuggestionWeight) / (mSuggestionsCountInStrip - 1);
40474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            }
40574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        }
40674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
4073e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka        private void setupTexts(final SuggestedWords suggestedWords, final int countInStrip) {
40874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            mTexts.clear();
409e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka            final int count = Math.min(suggestedWords.size(), countInStrip);
41060a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            for (int pos = 0; pos < count; pos++) {
411e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka                final CharSequence styled = getStyledSuggestionWord(suggestedWords, pos);
41274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                mTexts.add(styled);
41374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            }
41460a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            for (int pos = count; pos < countInStrip; pos++) {
41560a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                // Make this inactive for touches in layout().
41660a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                mTexts.add(null);
41760a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            }
41874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        }
41974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
4203e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka        private void layoutPunctuationSuggestions(final SuggestedWords suggestedWords,
4213e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka                final ViewGroup stripView) {
422e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka            final int countInStrip = Math.min(suggestedWords.size(), PUNCTUATIONS_IN_STRIP);
42360a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            for (int index = 0; index < countInStrip; index++) {
42460a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                if (index != 0) {
425913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka                    // Add divider if this isn't the left most suggestion in suggestions strip.
4262c47080e7b4b9b2a6c2dbf1444e041c1b7943316Tadashi G. Takaoka                    addDivider(stripView, mDividers.get(index));
42760a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                }
42860a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka
42960a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                final TextView word = mWords.get(index);
43060a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                word.setEnabled(true);
431a44685ab326809185a0e4c44afabe8fd93441b4cTadashi G. Takaoka                word.setTextColor(mColorAutoCorrect);
432bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka                final String text = suggestedWords.getWord(index);
43360a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                word.setText(text);
43460a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                word.setTextScaleX(1.0f);
435ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka                word.setCompoundDrawables(null, null, null, null);
43660a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                stripView.addView(word);
437913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka                setLayoutWeight(word, 1.0f, mSuggestionsStripHeight);
43860a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            }
439ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka            mMoreSuggestionsAvailable = false;
44074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        }
441c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka
442bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka        public void layoutAddToDictionaryHint(final String word, final ViewGroup stripView,
4433e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka                final int stripWidth, final CharSequence hintText, final OnClickListener listener) {
444c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            final int width = stripWidth - mDividerWidth - mPadding * 2;
445c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka
446c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            final TextView wordView = mWordToSaveView;
447c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            wordView.setTextColor(mColorTypedWord);
448913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka            final int wordWidth = (int)(width * mCenterSuggestionWeight);
449c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            final CharSequence text = getEllipsizedText(word, wordWidth, wordView.getPaint());
450c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            final float wordScaleX = wordView.getTextScaleX();
451c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            wordView.setTag(word);
452c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            wordView.setText(text);
453c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            wordView.setTextScaleX(wordScaleX);
454c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            stripView.addView(wordView);
455913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka            setLayoutWeight(wordView, mCenterSuggestionWeight, ViewGroup.LayoutParams.MATCH_PARENT);
456c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka
457c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            stripView.addView(mDividers.get(0));
458c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka
4592eb8781dc2e42d55474fb6e5c461c56c066b8363Tadashi G. Takaoka            final TextView leftArrowView = mLeftwardsArrowView;
4602eb8781dc2e42d55474fb6e5c461c56c066b8363Tadashi G. Takaoka            leftArrowView.setTextColor(mColorAutoCorrect);
4612eb8781dc2e42d55474fb6e5c461c56c066b8363Tadashi G. Takaoka            leftArrowView.setText(LEFTWARDS_ARROW);
4622eb8781dc2e42d55474fb6e5c461c56c066b8363Tadashi G. Takaoka            stripView.addView(leftArrowView);
4632eb8781dc2e42d55474fb6e5c461c56c066b8363Tadashi G. Takaoka
464c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            final TextView hintView = mHintToSaveView;
4652eb8781dc2e42d55474fb6e5c461c56c066b8363Tadashi G. Takaoka            hintView.setGravity(Gravity.LEFT | Gravity.CENTER_VERTICAL);
466c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            hintView.setTextColor(mColorAutoCorrect);
4672eb8781dc2e42d55474fb6e5c461c56c066b8363Tadashi G. Takaoka            final int hintWidth = width - wordWidth - leftArrowView.getWidth();
468644d33d60ea5a87501274488013d65f55238895eKen Wakasa            final float hintScaleX = getTextScaleX(hintText, hintWidth, hintView.getPaint());
469644d33d60ea5a87501274488013d65f55238895eKen Wakasa            hintView.setText(hintText);
470c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            hintView.setTextScaleX(hintScaleX);
471c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            stripView.addView(hintView);
472b8dc67466339dc14653ad634c86851025373326bTadashi G. Takaoka            setLayoutWeight(
473913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka                    hintView, 1.0f - mCenterSuggestionWeight, ViewGroup.LayoutParams.MATCH_PARENT);
4749f763d14451685965039990891eb0bc8e8db0735Tadashi G. Takaoka
4759f763d14451685965039990891eb0bc8e8db0735Tadashi G. Takaoka            wordView.setOnClickListener(listener);
4769f763d14451685965039990891eb0bc8e8db0735Tadashi G. Takaoka            leftArrowView.setOnClickListener(listener);
4779f763d14451685965039990891eb0bc8e8db0735Tadashi G. Takaoka            hintView.setOnClickListener(listener);
4789f763d14451685965039990891eb0bc8e8db0735Tadashi G. Takaoka        }
4799f763d14451685965039990891eb0bc8e8db0735Tadashi G. Takaoka
4809f763d14451685965039990891eb0bc8e8db0735Tadashi G. Takaoka        public CharSequence getAddToDictionaryWord() {
4819f763d14451685965039990891eb0bc8e8db0735Tadashi G. Takaoka            return (CharSequence)mWordToSaveView.getTag();
4829f763d14451685965039990891eb0bc8e8db0735Tadashi G. Takaoka        }
4839f763d14451685965039990891eb0bc8e8db0735Tadashi G. Takaoka
4843e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka        public boolean isAddToDictionaryShowing(final View v) {
4859f763d14451685965039990891eb0bc8e8db0735Tadashi G. Takaoka            return v == mWordToSaveView || v == mHintToSaveView || v == mLeftwardsArrowView;
486c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka        }
4872d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka
4883e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka        private static void setLayoutWeight(final View v, final float weight, final int height) {
4892d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka            final ViewGroup.LayoutParams lp = v.getLayoutParams();
4902d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka            if (lp instanceof LinearLayout.LayoutParams) {
4912d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka                final LinearLayout.LayoutParams llp = (LinearLayout.LayoutParams)lp;
4922d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka                llp.weight = weight;
4932d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka                llp.width = 0;
4942d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka                llp.height = height;
4952d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka            }
4962d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka        }
4972d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka
4983e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka        private static float getTextScaleX(final CharSequence text, final int maxWidth,
4993e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka                final TextPaint paint) {
5002d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka            paint.setTextScaleX(1.0f);
5012d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka            final int width = getTextWidth(text, paint);
5022d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka            if (width <= maxWidth) {
5032d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka                return 1.0f;
5042d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka            }
5052d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka            return maxWidth / (float)width;
5062d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka        }
5072d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka
5083e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka        private static CharSequence getEllipsizedText(final CharSequence text, final int maxWidth,
5093e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka                final TextPaint paint) {
5102d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka            if (text == null) return null;
5112d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka            paint.setTextScaleX(1.0f);
5122d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka            final int width = getTextWidth(text, paint);
5132d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka            if (width <= maxWidth) {
5142d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka                return text;
5152d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka            }
5162d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka            final float scaleX = maxWidth / (float)width;
5172d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka            if (scaleX >= MIN_TEXT_XSCALE) {
5182d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka                paint.setTextScaleX(scaleX);
5192d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka                return text;
5202d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka            }
5212d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka
5222d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka            // Note that TextUtils.ellipsize() use text-x-scale as 1.0 if ellipsize is needed. To
5232d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka            // get squeezed and ellipsized text, passes enlarged width (maxWidth / MIN_TEXT_XSCALE).
5242d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka            final CharSequence ellipsized = TextUtils.ellipsize(
5252d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka                    text, paint, maxWidth / MIN_TEXT_XSCALE, TextUtils.TruncateAt.MIDDLE);
5262d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka            paint.setTextScaleX(MIN_TEXT_XSCALE);
5272d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka            return ellipsized;
5282d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka        }
5292d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka
5303e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka        private static int getTextWidth(final CharSequence text, final TextPaint paint) {
5312d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka            if (TextUtils.isEmpty(text)) return 0;
5322d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka            final Typeface savedTypeface = paint.getTypeface();
5332d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka            paint.setTypeface(getTextTypeface(text));
5342d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka            final int len = text.length();
5352d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka            final float[] widths = new float[len];
5362d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka            final int count = paint.getTextWidths(text, 0, len, widths);
5372d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka            int width = 0;
5382d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka            for (int i = 0; i < count; i++) {
5392d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka                width += Math.round(widths[i] + 0.5f);
5402d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka            }
5412d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka            paint.setTypeface(savedTypeface);
5422d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka            return width;
5432d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka        }
5442d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka
5453e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka        private static Typeface getTextTypeface(final CharSequence text) {
5462d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka            if (!(text instanceof SpannableString))
5472d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka                return Typeface.DEFAULT;
5482d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka
5492d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka            final SpannableString ss = (SpannableString)text;
5502d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka            final StyleSpan[] styles = ss.getSpans(0, text.length(), StyleSpan.class);
5512d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka            if (styles.length == 0)
5522d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka                return Typeface.DEFAULT;
5532d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka
5542d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka            switch (styles[0].getStyle()) {
5552d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka            case Typeface.BOLD: return Typeface.DEFAULT_BOLD;
5562d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka            // TODO: BOLD_ITALIC, ITALIC case?
5572d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka            default: return Typeface.DEFAULT;
5582d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka            }
5592d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka        }
56074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka    }
56174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
562923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    /**
5634702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka     * Construct a {@link SuggestionStripView} for showing suggestions to be picked by the user.
564923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     * @param context
565923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     * @param attrs
566923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     */
5673e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka    public SuggestionStripView(final Context context, final AttributeSet attrs) {
5684702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka        this(context, attrs, R.attr.suggestionStripViewStyle);
56908a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka    }
57008a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka
5713e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka    public SuggestionStripView(final Context context, final AttributeSet attrs,
5723e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka            final int defStyle) {
573c412309b7a32308b1b0a175dafc13f90254353c5Tadashi G. Takaoka        super(context, attrs, defStyle);
574923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
57516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka        final LayoutInflater inflater = LayoutInflater.from(context);
576913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka        inflater.inflate(R.layout.suggestions_strip, this);
57786e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka
578913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka        mSuggestionsStrip = (ViewGroup)findViewById(R.id.suggestions_strip);
57960a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka        for (int pos = 0; pos < MAX_SUGGESTIONS; pos++) {
580913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka            final TextView word = (TextView)inflater.inflate(R.layout.suggestion_word, null);
58160a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            word.setTag(pos);
5822442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka            word.setOnClickListener(this);
583ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka            word.setOnLongClickListener(this);
5842442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka            mWords.add(word);
585913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka            final View divider = inflater.inflate(R.layout.suggestion_divider, null);
58660a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            divider.setTag(pos);
587a1aab83a24e74cb0fad4b1c1e59b18d23ecbdad3Tadashi G. Takaoka            divider.setOnClickListener(this);
588a1aab83a24e74cb0fad4b1c1e59b18d23ecbdad3Tadashi G. Takaoka            mDividers.add(divider);
589913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka            mInfos.add((TextView)inflater.inflate(R.layout.suggestion_info, null));
590c9716b28ce438e06b5cacc07fc002944bcbe24a0Tadashi G. Takaoka        }
591179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaoka
5924702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka        mParams = new SuggestionStripViewParams(
5934702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka                context, attrs, defStyle, mWords, mDividers, mInfos);
59429e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka
59529e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka        mMoreSuggestionsContainer = inflater.inflate(R.layout.more_suggestions, null);
59629e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka        mMoreSuggestionsView = (MoreSuggestionsView)mMoreSuggestionsContainer
59729e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka                .findViewById(R.id.more_suggestions_view);
59829e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka        mMoreSuggestionsBuilder = new MoreSuggestions.Builder(mMoreSuggestionsView);
599bfc1d732ac92fa1bd5b19ad9e7c71ce9a1f9dc00Tadashi G. Takaoka
60050e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka        final Resources res = context.getResources();
60150e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka        mMoreSuggestionsModalTolerance = res.getDimensionPixelOffset(
60250e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka                R.dimen.more_suggestions_modal_tolerance);
6033fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka        mMoreSuggestionsSlidingDetector = new GestureDetector(
6043fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka                context, mMoreSuggestionsSlidingListener);
605923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
606c9716b28ce438e06b5cacc07fc002944bcbe24a0Tadashi G. Takaoka
607923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    /**
608c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka     * A connection back to the input method.
609923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     * @param listener
610923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     */
6113e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka    public void setListener(final Listener listener, final View inputView) {
612c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka        mListener = listener;
613d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka        mMainKeyboardView = (MainKeyboardView)inputView.findViewById(R.id.keyboard_view);
614923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
615923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
6163e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka    public void setSuggestions(final SuggestedWords suggestedWords) {
617e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        clear();
618e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka        mSuggestedWords = suggestedWords;
619e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka        mParams.layout(mSuggestedWords, mSuggestionsStrip, this, getWidth());
620a9ca7867b5a7c0be115966211a05f5d460c8638cKurt Partridge        if (ProductionFlag.IS_EXPERIMENTAL) {
6214702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka            ResearchLogger.suggestionStripView_setSuggestions(mSuggestedWords);
622a9ca7867b5a7c0be115966211a05f5d460c8638cKurt Partridge        }
62316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka    }
62474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
6253e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka    public int setMoreSuggestionsHeight(final int remainingHeight) {
626c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka        return mParams.setMoreSuggestionsHeight(remainingHeight);
627c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka    }
628b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka
629b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani    public boolean isShowingAddToDictionaryHint() {
630913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka        return mSuggestionsStrip.getChildCount() > 0
6319f763d14451685965039990891eb0bc8e8db0735Tadashi G. Takaoka                && mParams.isAddToDictionaryShowing(mSuggestionsStrip.getChildAt(0));
632b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani    }
633b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani
634bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka    public void showAddToDictionaryHint(final String word, final CharSequence hintText) {
635c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka        clear();
6369f763d14451685965039990891eb0bc8e8db0735Tadashi G. Takaoka        mParams.layoutAddToDictionaryHint(word, mSuggestionsStrip, getWidth(), hintText, this);
63766a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani    }
63866a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani
6396558253160e2039c87f424bd814f402ecd31de3bKen Wakasa    public boolean dismissAddToDictionaryHint() {
640c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka        if (isShowingAddToDictionaryHint()) {
641c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            clear();
642c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            return true;
643c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka        }
644c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka        return false;
6456558253160e2039c87f424bd814f402ecd31de3bKen Wakasa    }
6466558253160e2039c87f424bd814f402ecd31de3bKen Wakasa
6477e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka    public SuggestedWords getSuggestions() {
648e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka        return mSuggestedWords;
649979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
650979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
651923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void clear() {
652913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka        mSuggestionsStrip.removeAllViews();
653c412309b7a32308b1b0a175dafc13f90254353c5Tadashi G. Takaoka        removeAllViews();
654c412309b7a32308b1b0a175dafc13f90254353c5Tadashi G. Takaoka        addView(mSuggestionsStrip);
6551b087064c07975c5e2b9c17d4ca80c56e01c35c0Tadashi G. Takaoka        dismissMoreSuggestions();
656923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
657923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
65829e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka    private final KeyboardActionListener mMoreSuggestionsListener =
65929e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka            new KeyboardActionListener.Adapter() {
66029e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka        @Override
6613e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka        public boolean onCustomRequest(final int requestCode) {
66229e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka            final int index = requestCode;
663bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka            final String word = mSuggestedWords.getWord(index);
6646785b9072762e15bb49657ce7b7d228dab76e44aTadashi G. Takaoka            mListener.pickSuggestionManually(index, word);
6651b087064c07975c5e2b9c17d4ca80c56e01c35c0Tadashi G. Takaoka            dismissMoreSuggestions();
66629e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka            return true;
66729e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka        }
66829e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka
66929e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka        @Override
67029e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka        public void onCancelInput() {
6711b087064c07975c5e2b9c17d4ca80c56e01c35c0Tadashi G. Takaoka            dismissMoreSuggestions();
67229e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka        }
67329e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka    };
67429e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka
67529e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka    private final MoreKeysPanel.Controller mMoreSuggestionsController =
67629e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka            new MoreKeysPanel.Controller() {
67729e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka        @Override
678fa2d543785c52f639ad3157c57420f58a199c550Tom Ouyang        public boolean onDismissMoreKeysPanel() {
679d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka            return mMainKeyboardView.onDismissMoreKeysPanel();
680fa2d543785c52f639ad3157c57420f58a199c550Tom Ouyang        }
681fa2d543785c52f639ad3157c57420f58a199c550Tom Ouyang
682fa2d543785c52f639ad3157c57420f58a199c550Tom Ouyang        @Override
683a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka        public void onShowMoreKeysPanel(final MoreKeysPanel panel) {
684d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka            mMainKeyboardView.onShowMoreKeysPanel(panel);
68529e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka        }
686ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang
687ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang        @Override
688ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang        public void onCancelMoreKeysPanel() {
689ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang            dismissMoreSuggestions();
690ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang        }
69129e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka    };
69229e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka
6933e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka    boolean dismissMoreSuggestions() {
694fa2d543785c52f639ad3157c57420f58a199c550Tom Ouyang        return mMoreSuggestionsView.dismissMoreKeysPanel();
6951b087064c07975c5e2b9c17d4ca80c56e01c35c0Tadashi G. Takaoka    }
6961b087064c07975c5e2b9c17d4ca80c56e01c35c0Tadashi G. Takaoka
697e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka    @Override
6983e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka    public boolean onLongClick(final View view) {
6995faf41951929301af80026bc3191812ef874fd5aTadashi G. Takaoka        KeyboardSwitcher.getInstance().hapticAndAudioFeedback(Constants.NOT_A_CODE);
7003fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka        return showMoreSuggestions();
7013fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka    }
7023fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka
7033e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka    boolean showMoreSuggestions() {
7047339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka        final Keyboard parentKeyboard = KeyboardSwitcher.getInstance().getKeyboard();
7057339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka        if (parentKeyboard == null) {
7067339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka            return false;
707ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka        }
7087339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka        final SuggestionStripViewParams params = mParams;
7097339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka        if (!params.mMoreSuggestionsAvailable) {
7107339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka            return false;
7117339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka        }
7127339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka        final int stripWidth = getWidth();
7137339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka        final View container = mMoreSuggestionsContainer;
7147339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka        final int maxWidth = stripWidth - container.getPaddingLeft() - container.getPaddingRight();
7157339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka        final MoreSuggestions.Builder builder = mMoreSuggestionsBuilder;
7167339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka        builder.layout(mSuggestedWords, params.mSuggestionsCountInStrip, maxWidth,
7177339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka                (int)(maxWidth * params.mMinMoreSuggestionsWidth),
7187339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka                params.getMaxMoreSuggestionsRow(), parentKeyboard);
7197339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka        mMoreSuggestionsView.setKeyboard(builder.build());
7207339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka        container.measure(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
7217339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka
7227339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka        final MoreKeysPanel moreKeysPanel = mMoreSuggestionsView;
7237339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka        final int pointX = stripWidth / 2;
7247339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka        final int pointY = -params.mMoreSuggestionsBottomGap;
7257339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka        moreKeysPanel.showMoreKeysPanel(this, mMoreSuggestionsController, pointX, pointY,
726fa2d543785c52f639ad3157c57420f58a199c550Tom Ouyang                mMoreSuggestionsListener);
7277339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka        mMoreSuggestionsMode = MORE_SUGGESTIONS_CHECKING_MODAL_OR_SLIDING;
7287339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka        mOriginX = mLastX;
7297339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka        mOriginY = mLastY;
7307339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka        for (int i = 0; i < params.mSuggestionsCountInStrip; i++) {
7317339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka            mWords.get(i).setPressed(false);
7327339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka        }
7337339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka        return true;
734ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka    }
735ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka
73650e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka    // Working variables for onLongClick and dispatchTouchEvent.
737d7b00f34904c61f955e439160e2dbaa3a4b6983cTadashi G. Takaoka    private int mMoreSuggestionsMode = MORE_SUGGESTIONS_IN_MODAL_MODE;
738d7b00f34904c61f955e439160e2dbaa3a4b6983cTadashi G. Takaoka    private static final int MORE_SUGGESTIONS_IN_MODAL_MODE = 0;
739d7b00f34904c61f955e439160e2dbaa3a4b6983cTadashi G. Takaoka    private static final int MORE_SUGGESTIONS_CHECKING_MODAL_OR_SLIDING = 1;
740d7b00f34904c61f955e439160e2dbaa3a4b6983cTadashi G. Takaoka    private static final int MORE_SUGGESTIONS_IN_SLIDING_MODE = 2;
74150e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka    private int mLastX;
74250e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka    private int mLastY;
74350e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka    private int mOriginX;
74450e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka    private int mOriginY;
74550e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka    private final int mMoreSuggestionsModalTolerance;
7463fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka    private final GestureDetector mMoreSuggestionsSlidingDetector;
7473fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka    private final GestureDetector.OnGestureListener mMoreSuggestionsSlidingListener =
7483fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka            new GestureDetector.SimpleOnGestureListener() {
7493fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka        @Override
7503fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka        public boolean onScroll(MotionEvent down, MotionEvent me, float deltaX, float deltaY) {
7513fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka            final float dy = me.getY() - down.getY();
7523fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka            if (deltaY > 0 && dy < 0) {
7533fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka                return showMoreSuggestions();
7543fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka            }
7553fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka            return false;
7563fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka        }
7573fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka    };
75850e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka
759ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka    @Override
7603e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka    public boolean dispatchTouchEvent(final MotionEvent me) {
761fa2d543785c52f639ad3157c57420f58a199c550Tom Ouyang        if (!mMoreSuggestionsView.isShowingInParent()
762d7b00f34904c61f955e439160e2dbaa3a4b6983cTadashi G. Takaoka                || mMoreSuggestionsMode == MORE_SUGGESTIONS_IN_MODAL_MODE) {
76350e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka            mLastX = (int)me.getX();
76450e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka            mLastY = (int)me.getY();
7653fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka            if (mMoreSuggestionsSlidingDetector.onTouchEvent(me)) {
7663fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka                return true;
7673fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka            }
76829e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka            return super.dispatchTouchEvent(me);
76929e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka        }
7708ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka
7718ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka        final MoreKeysPanel moreKeysPanel = mMoreSuggestionsView;
77229e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka        final int action = me.getAction();
77329e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka        final long eventTime = me.getEventTime();
77429e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka        final int index = me.getActionIndex();
77529e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka        final int id = me.getPointerId(index);
7768ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka        final int x = (int)me.getX(index);
7778ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka        final int y = (int)me.getY(index);
7788ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka        final int translatedX = moreKeysPanel.translateX(x);
7798ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka        final int translatedY = moreKeysPanel.translateY(y);
7808ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka
781d7b00f34904c61f955e439160e2dbaa3a4b6983cTadashi G. Takaoka        if (mMoreSuggestionsMode == MORE_SUGGESTIONS_CHECKING_MODAL_OR_SLIDING) {
78287104bace9cb9ed1a700f05a37743a21c2722fffTadashi G. Takaoka            if (Math.abs(x - mOriginX) >= mMoreSuggestionsModalTolerance
78387104bace9cb9ed1a700f05a37743a21c2722fffTadashi G. Takaoka                    || mOriginY - y >= mMoreSuggestionsModalTolerance) {
78487104bace9cb9ed1a700f05a37743a21c2722fffTadashi G. Takaoka                // Decided to be in the sliding input mode only when the touch point has been moved
78587104bace9cb9ed1a700f05a37743a21c2722fffTadashi G. Takaoka                // upward.
786d7b00f34904c61f955e439160e2dbaa3a4b6983cTadashi G. Takaoka                mMoreSuggestionsMode = MORE_SUGGESTIONS_IN_SLIDING_MODE;
78750e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka            } else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_POINTER_UP) {
78850e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka                // Decided to be in the modal input mode
789d7b00f34904c61f955e439160e2dbaa3a4b6983cTadashi G. Takaoka                mMoreSuggestionsMode = MORE_SUGGESTIONS_IN_MODAL_MODE;
79050e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka            }
79150e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka            return true;
79250e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka        }
79350e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka
794d7b00f34904c61f955e439160e2dbaa3a4b6983cTadashi G. Takaoka        // MORE_SUGGESTIONS_IN_SLIDING_MODE
79535580bad6f3da3b204653825bbb6871563e70728Tom Ouyang        mMoreSuggestionsView.processMotionEvent(action, translatedX, translatedY, id, eventTime);
79629e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka        return true;
79729e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka    }
79829e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka
79929e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka    @Override
8003e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka    public void onClick(final View view) {
8019f763d14451685965039990891eb0bc8e8db0735Tadashi G. Takaoka        if (mParams.isAddToDictionaryShowing(view)) {
8023d8e7a62fc6182c12ca28c29ceeee52ed4b9eea7Jean Chalard            mListener.addWordToUserDictionary(mParams.getAddToDictionaryWord().toString());
803717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka            clear();
804717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka            return;
805717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka        }
806717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka
80786e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        final Object tag = view.getTag();
80886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        if (!(tag instanceof Integer))
80986e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka            return;
81086e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        final int index = (Integer) tag;
811e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka        if (index >= mSuggestedWords.size())
81237deb112c727dfed5e94d054cf5f00f5d60c8120Tadashi G. Takaoka            return;
81386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka
814bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka        final String word = mSuggestedWords.getWord(index);
8156785b9072762e15bb49657ce7b7d228dab76e44aTadashi G. Takaoka        mListener.pickSuggestionManually(index, word);
816923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
81782411d47ba7e8133ed2390c6920945e139a738cesatok
8186ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani    @Override
81973cd4c1428ac370e1c15c5f61b1ce499f0d4f4c7Tadashi G. Takaoka    protected void onDetachedFromWindow() {
8206ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani        super.onDetachedFromWindow();
82132f4ceb2434b6f204cf8152b406d0f9a642feb73Tadashi G. Takaoka        dismissMoreSuggestions();
8226ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani    }
823923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project}
824