SuggestionStripView.java revision 18d688c94bb8e1e26de2d12445cb3096c6126f75
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
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;
30bfc1d732ac92fa1bd5b19ad9e7c71ce9a1f9dc00Tadashi G. Takaokaimport android.graphics.drawable.ColorDrawable;
31e583371b13ebd9aa336d0883e8c174ae4918c758Tadashi G. Takaokaimport android.graphics.drawable.Drawable;
32e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaokaimport android.os.Message;
33522d5c16d20657e7d26009fe9c067404e16a6c2aTadashi G. Takaokaimport android.text.Spannable;
34522d5c16d20657e7d26009fe9c067404e16a6c2aTadashi G. Takaokaimport android.text.SpannableString;
35e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaokaimport android.text.Spanned;
36b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaokaimport android.text.TextPaint;
37e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaokaimport android.text.TextUtils;
38522d5c16d20657e7d26009fe9c067404e16a6c2aTadashi G. Takaokaimport android.text.style.CharacterStyle;
3974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaokaimport android.text.style.StyleSpan;
40522d5c16d20657e7d26009fe9c067404e16a6c2aTadashi G. Takaokaimport android.text.style.UnderlineSpan;
41923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.util.AttributeSet;
423fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaokaimport android.view.GestureDetector;
43923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.Gravity;
44923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.LayoutInflater;
4529e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaokaimport android.view.MotionEvent;
46923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.View;
47e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaokaimport android.view.View.OnClickListener;
48ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaokaimport android.view.View.OnLongClickListener;
49e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaokaimport android.view.ViewGroup;
50e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaokaimport android.widget.LinearLayout;
51923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.widget.PopupWindow;
52c412309b7a32308b1b0a175dafc13f90254353c5Tadashi G. Takaokaimport android.widget.RelativeLayout;
53923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.widget.TextView;
54923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
5529e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaokaimport com.android.inputmethod.keyboard.KeyboardActionListener;
561b087064c07975c5e2b9c17d4ca80c56e01c35c0Tadashi G. Takaokaimport com.android.inputmethod.keyboard.KeyboardView;
5729e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaokaimport com.android.inputmethod.keyboard.MoreKeysPanel;
5829e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaokaimport com.android.inputmethod.keyboard.PointerTracker;
59c8461d1ae26d43a09c0f835d833f3d49fbe8d2f3Tadashi G. Takaokaimport com.android.inputmethod.keyboard.ViewLayoutUtils;
60f72b8f5662afb42b08eb88e92731d52f99df13e3Jean Chalardimport com.android.inputmethod.latin.AutoCorrection;
615f282ea9e4a4590fcbab6e27d5fca7dacbb40a6aTadashi G. Takaokaimport com.android.inputmethod.latin.CollectionUtils;
628c3d5b6961a9b9d40c4bf21ad495f852971c24f4Tadashi G. Takaokaimport com.android.inputmethod.latin.LatinImeLogger;
638c3d5b6961a9b9d40c4bf21ad495f852971c24f4Tadashi G. Takaokaimport com.android.inputmethod.latin.R;
6492821614fd80112527e133f069e31ee48250314fTadashi G. Takaokaimport com.android.inputmethod.latin.ResourceUtils;
658c3d5b6961a9b9d40c4bf21ad495f852971c24f4Tadashi G. Takaokaimport com.android.inputmethod.latin.StaticInnerHandlerWrapper;
668c3d5b6961a9b9d40c4bf21ad495f852971c24f4Tadashi G. Takaokaimport com.android.inputmethod.latin.SuggestedWords;
67042557b45bf2554608cd22874633011157cd1752Jean Chalardimport com.android.inputmethod.latin.Utils;
68a9ca7867b5a7c0be115966211a05f5d460c8638cKurt Partridgeimport com.android.inputmethod.latin.define.ProductionFlag;
696b966160ac8570271547bf63217efa5e228d4accKurt Partridgeimport com.android.inputmethod.research.ResearchLogger;
70ddb61ea461b920d87be4ad78c8a36eec1013b965Tadashi G. Takaoka
71179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaokaimport java.util.ArrayList;
72179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaoka
73a28a05e971cc242b338331a3b78276fa95188d19Tadashi G. Takaokapublic final class SuggestionStripView extends RelativeLayout implements OnClickListener,
74c412309b7a32308b1b0a175dafc13f90254353c5Tadashi G. Takaoka        OnLongClickListener {
75c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka    public interface Listener {
7618d688c94bb8e1e26de2d12445cb3096c6126f75Jean Chalard        public void addWordToUserDictionary(String word);
776785b9072762e15bb49657ce7b7d228dab76e44aTadashi G. Takaoka        public void pickSuggestionManually(int index, CharSequence word);
78c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka    }
79c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka
8086e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka    // The maximum number of suggestions available. See {@link Suggest#mPrefMaxSuggestions}.
8129e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka    public static final int MAX_SUGGESTIONS = 18;
82923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
838c3d5b6961a9b9d40c4bf21ad495f852971c24f4Tadashi G. Takaoka    static final boolean DBG = LatinImeLogger.sDBG;
846f7218627eda110a8454053f8ecb7b80edfdc8cesatok
85913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka    private final ViewGroup mSuggestionsStrip;
861b087064c07975c5e2b9c17d4ca80c56e01c35c0Tadashi G. Takaoka    private KeyboardView mKeyboardView;
8774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
8829e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka    private final View mMoreSuggestionsContainer;
8929e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka    private final MoreSuggestionsView mMoreSuggestionsView;
9029e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka    private final MoreSuggestions.Builder mMoreSuggestionsBuilder;
9129e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka    private final PopupWindow mMoreSuggestionsWindow;
9229e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka
935f282ea9e4a4590fcbab6e27d5fca7dacbb40a6aTadashi G. Takaoka    private final ArrayList<TextView> mWords = CollectionUtils.newArrayList();
945f282ea9e4a4590fcbab6e27d5fca7dacbb40a6aTadashi G. Takaoka    private final ArrayList<TextView> mInfos = CollectionUtils.newArrayList();
955f282ea9e4a4590fcbab6e27d5fca7dacbb40a6aTadashi G. Takaoka    private final ArrayList<View> mDividers = CollectionUtils.newArrayList();
9674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
9782411d47ba7e8133ed2390c6920945e139a738cesatok    private final PopupWindow mPreviewPopup;
9882411d47ba7e8133ed2390c6920945e139a738cesatok    private final TextView mPreviewText;
9966a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani
100c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka    private Listener mListener;
101e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka    private SuggestedWords mSuggestedWords = SuggestedWords.EMPTY;
1026a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani
1034702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka    private final SuggestionStripViewParams mParams;
104ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka    private static final float MIN_TEXT_XSCALE = 0.70f;
105b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka
1064f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa    private final UiHandler mHandler = new UiHandler(this);
10755b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka
108a28a05e971cc242b338331a3b78276fa95188d19Tadashi G. Takaoka    private static final class UiHandler extends StaticInnerHandlerWrapper<SuggestionStripView> {
10955b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        private static final int MSG_HIDE_PREVIEW = 0;
11055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka
1114702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka        public UiHandler(SuggestionStripView outerInstance) {
1124f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa            super(outerInstance);
1134f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa        }
1144f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa
115e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        @Override
116e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        public void dispatchMessage(Message msg) {
1174702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka            final SuggestionStripView suggestionStripView = getOuterInstance();
118e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka            switch (msg.what) {
119e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka            case MSG_HIDE_PREVIEW:
1204702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka                suggestionStripView.hidePreview();
121e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka                break;
122e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka            }
123e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        }
12455b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka
12555b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        public void cancelHidePreview() {
12655b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            removeMessages(MSG_HIDE_PREVIEW);
12755b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        }
12855b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka
12955b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        public void cancelAllMessages() {
13055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            cancelHidePreview();
13155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        }
132e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka    }
133179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaoka
134a28a05e971cc242b338331a3b78276fa95188d19Tadashi G. Takaoka    private static final class SuggestionStripViewParams {
135d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka        private static final int DEFAULT_SUGGESTIONS_COUNT_IN_STRIP = 3;
136ef2bfad5903fb55adca61dbea51984fbc7e4375fTadashi G. Takaoka        private static final float DEFAULT_CENTER_SUGGESTION_PERCENTILE = 0.40f;
1379676038b6e9fb66760588d7f9c9c642cc493dd71Tadashi G. Takaoka        private static final int DEFAULT_MAX_MORE_SUGGESTIONS_ROW = 2;
138293db0873fd89b5c2bd077ffa5091321b3ab8149Ken Wakasa        private static final int PUNCTUATIONS_IN_STRIP = 5;
139d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka
14074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        public final int mPadding;
14174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        public final int mDividerWidth;
142913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka        public final int mSuggestionsStripHeight;
143d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka        public final int mSuggestionsCountInStrip;
144c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka        public final int mMoreSuggestionsRowHeight;
145c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka        private int mMaxMoreSuggestionsRow;
1469676038b6e9fb66760588d7f9c9c642cc493dd71Tadashi G. Takaoka        public final float mMinMoreSuggestionsWidth;
1474269a7cebdfe5c76372d0f0dd187432f0594ffe5Tadashi G. Takaoka        public final int mMoreSuggestionsBottomGap;
14816713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka
149660776e09b9a3b321074a94721d901a035ca1b9fKen Wakasa        private final ArrayList<TextView> mWords;
150660776e09b9a3b321074a94721d901a035ca1b9fKen Wakasa        private final ArrayList<View> mDividers;
151660776e09b9a3b321074a94721d901a035ca1b9fKen Wakasa        private final ArrayList<TextView> mInfos;
152d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka
153a44685ab326809185a0e4c44afabe8fd93441b4cTadashi G. Takaoka        private final int mColorValidTypedWord;
154d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        private final int mColorTypedWord;
155d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        private final int mColorAutoCorrect;
156913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka        private final int mColorSuggested;
157697bf585f8dac6ffc4d008c02b63407cfdd83104Tadashi G. Takaoka        private final float mAlphaObsoleted;
158913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka        private final float mCenterSuggestionWeight;
159913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka        private final int mCenterSuggestionIndex;
160913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka        private final Drawable mMoreSuggestionsHint;
1619bdce3a59e9bf00095bc92fae88b830b0a8455beFabrice Di Meglio        private static final String MORE_SUGGESTIONS_HINT = "\u2026";
1622eb8781dc2e42d55474fb6e5c461c56c066b8363Tadashi G. Takaoka        private static final String LEFTWARDS_ARROW = "\u2190";
163d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka
164d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        private static final CharacterStyle BOLD_SPAN = new StyleSpan(Typeface.BOLD);
165d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        private static final CharacterStyle UNDERLINE_SPAN = new UnderlineSpan();
166d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        private static final int AUTO_CORRECT_BOLD = 0x01;
167d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        private static final int AUTO_CORRECT_UNDERLINE = 0x02;
16877a87e3cb5886b1319230906c77c0bc98b905248Tadashi G. Takaoka        private static final int VALID_TYPED_WORD_BOLD = 0x04;
169d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka
170d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka        private final int mSuggestionStripOption;
17174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
1725f282ea9e4a4590fcbab6e27d5fca7dacbb40a6aTadashi G. Takaoka        private final ArrayList<CharSequence> mTexts = CollectionUtils.newArrayList();
17374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
174ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka        public boolean mMoreSuggestionsAvailable;
175ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka
1769f763d14451685965039990891eb0bc8e8db0735Tadashi G. Takaoka        private final TextView mWordToSaveView;
1772eb8781dc2e42d55474fb6e5c461c56c066b8363Tadashi G. Takaoka        private final TextView mLeftwardsArrowView;
178c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka        private final TextView mHintToSaveView;
179c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka
1804702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka        public SuggestionStripViewParams(Context context, AttributeSet attrs, int defStyle,
181660776e09b9a3b321074a94721d901a035ca1b9fKen Wakasa                ArrayList<TextView> words, ArrayList<View> dividers, ArrayList<TextView> infos) {
182d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka            mWords = words;
183d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka            mDividers = dividers;
184d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka            mInfos = infos;
185d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka
186d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka            final TextView word = words.get(0);
187d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka            final View divider = dividers.get(0);
188d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka            mPadding = word.getCompoundPaddingLeft() + word.getCompoundPaddingRight();
189d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka            divider.measure(
190d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka                    ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
191d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka            mDividerWidth = divider.getMeasuredWidth();
192d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka
193d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka            final Resources res = word.getResources();
194d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka            mSuggestionsStripHeight = res.getDimensionPixelSize(R.dimen.suggestions_strip_height);
195d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka
1964702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka            final TypedArray a = context.obtainStyledAttributes(attrs,
1974702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka                    R.styleable.SuggestionStripView, defStyle, R.style.SuggestionStripViewStyle);
1984702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka            mSuggestionStripOption = a.getInt(
1994702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka                    R.styleable.SuggestionStripView_suggestionStripOption, 0);
20092821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka            final float alphaValidTypedWord = ResourceUtils.getFraction(a,
201ef2bfad5903fb55adca61dbea51984fbc7e4375fTadashi G. Takaoka                    R.styleable.SuggestionStripView_alphaValidTypedWord, 1.0f);
20292821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka            final float alphaTypedWord = ResourceUtils.getFraction(a,
203ef2bfad5903fb55adca61dbea51984fbc7e4375fTadashi G. Takaoka                    R.styleable.SuggestionStripView_alphaTypedWord, 1.0f);
20492821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka            final float alphaAutoCorrect = ResourceUtils.getFraction(a,
205ef2bfad5903fb55adca61dbea51984fbc7e4375fTadashi G. Takaoka                    R.styleable.SuggestionStripView_alphaAutoCorrect, 1.0f);
20692821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka            final float alphaSuggested = ResourceUtils.getFraction(a,
207ef2bfad5903fb55adca61dbea51984fbc7e4375fTadashi G. Takaoka                    R.styleable.SuggestionStripView_alphaSuggested, 1.0f);
20892821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka            mAlphaObsoleted = ResourceUtils.getFraction(a,
209ef2bfad5903fb55adca61dbea51984fbc7e4375fTadashi G. Takaoka                    R.styleable.SuggestionStripView_alphaSuggested, 1.0f);
2104702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka            mColorValidTypedWord = applyAlpha(a.getColor(
2114702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka                    R.styleable.SuggestionStripView_colorValidTypedWord, 0), alphaValidTypedWord);
2124702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka            mColorTypedWord = applyAlpha(a.getColor(
2134702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka                    R.styleable.SuggestionStripView_colorTypedWord, 0), alphaTypedWord);
2144702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka            mColorAutoCorrect = applyAlpha(a.getColor(
2154702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka                    R.styleable.SuggestionStripView_colorAutoCorrect, 0), alphaAutoCorrect);
2164702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka            mColorSuggested = applyAlpha(a.getColor(
2174702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka                    R.styleable.SuggestionStripView_colorSuggested, 0), alphaSuggested);
218913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka            mSuggestionsCountInStrip = a.getInt(
2194702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka                    R.styleable.SuggestionStripView_suggestionsCountInStrip,
220913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka                    DEFAULT_SUGGESTIONS_COUNT_IN_STRIP);
22192821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka            mCenterSuggestionWeight = ResourceUtils.getFraction(a,
2224702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka                    R.styleable.SuggestionStripView_centerSuggestionPercentile,
223697bf585f8dac6ffc4d008c02b63407cfdd83104Tadashi G. Takaoka                    DEFAULT_CENTER_SUGGESTION_PERCENTILE);
2249676038b6e9fb66760588d7f9c9c642cc493dd71Tadashi G. Takaoka            mMaxMoreSuggestionsRow = a.getInt(
2254702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka                    R.styleable.SuggestionStripView_maxMoreSuggestionsRow,
2269676038b6e9fb66760588d7f9c9c642cc493dd71Tadashi G. Takaoka                    DEFAULT_MAX_MORE_SUGGESTIONS_ROW);
22792821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka            mMinMoreSuggestionsWidth = ResourceUtils.getFraction(a,
228ef2bfad5903fb55adca61dbea51984fbc7e4375fTadashi G. Takaoka                    R.styleable.SuggestionStripView_minMoreSuggestionsWidth, 1.0f);
229d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            a.recycle();
230d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka
2310967ef40368c4bc7a0576ecc3dc222a8fe9b94c3Tadashi G. Takaoka            mMoreSuggestionsHint = getMoreSuggestionsHint(res,
2320967ef40368c4bc7a0576ecc3dc222a8fe9b94c3Tadashi G. Takaoka                    res.getDimension(R.dimen.more_suggestions_hint_text_size), mColorAutoCorrect);
233913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka            mCenterSuggestionIndex = mSuggestionsCountInStrip / 2;
2344269a7cebdfe5c76372d0f0dd187432f0594ffe5Tadashi G. Takaoka            mMoreSuggestionsBottomGap = res.getDimensionPixelOffset(
2354269a7cebdfe5c76372d0f0dd187432f0594ffe5Tadashi G. Takaoka                    R.dimen.more_suggestions_bottom_gap);
236c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka            mMoreSuggestionsRowHeight = res.getDimensionPixelSize(
237c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka                    R.dimen.more_suggestions_row_height);
23860a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka
239c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            final LayoutInflater inflater = LayoutInflater.from(context);
240913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka            mWordToSaveView = (TextView)inflater.inflate(R.layout.suggestion_word, null);
2412eb8781dc2e42d55474fb6e5c461c56c066b8363Tadashi G. Takaoka            mLeftwardsArrowView = (TextView)inflater.inflate(R.layout.hint_add_to_dictionary, null);
2422eb8781dc2e42d55474fb6e5c461c56c066b8363Tadashi G. Takaoka            mHintToSaveView = (TextView)inflater.inflate(R.layout.hint_add_to_dictionary, null);
24374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        }
24474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
245c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka        public int getMaxMoreSuggestionsRow() {
246c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka            return mMaxMoreSuggestionsRow;
247c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka        }
248c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka
249c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka        private int getMoreSuggestionsHeight() {
250c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka            return mMaxMoreSuggestionsRow * mMoreSuggestionsRowHeight + mMoreSuggestionsBottomGap;
251c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka        }
252c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka
253c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka        public int setMoreSuggestionsHeight(int remainingHeight) {
254c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka            final int currentHeight = getMoreSuggestionsHeight();
255c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka            if (currentHeight <= remainingHeight) {
256c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka                return currentHeight;
257c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka            }
258c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka
259c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka            mMaxMoreSuggestionsRow = (remainingHeight - mMoreSuggestionsBottomGap)
260c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka                    / mMoreSuggestionsRowHeight;
261c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka            final int newHeight = getMoreSuggestionsHeight();
262c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka            return newHeight;
263c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka        }
264c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka
2650967ef40368c4bc7a0576ecc3dc222a8fe9b94c3Tadashi G. Takaoka        private static Drawable getMoreSuggestionsHint(Resources res, float textSize, int color) {
2660967ef40368c4bc7a0576ecc3dc222a8fe9b94c3Tadashi G. Takaoka            final Paint paint = new Paint();
2670967ef40368c4bc7a0576ecc3dc222a8fe9b94c3Tadashi G. Takaoka            paint.setAntiAlias(true);
2680967ef40368c4bc7a0576ecc3dc222a8fe9b94c3Tadashi G. Takaoka            paint.setTextAlign(Align.CENTER);
2690967ef40368c4bc7a0576ecc3dc222a8fe9b94c3Tadashi G. Takaoka            paint.setTextSize(textSize);
2700967ef40368c4bc7a0576ecc3dc222a8fe9b94c3Tadashi G. Takaoka            paint.setColor(color);
2710967ef40368c4bc7a0576ecc3dc222a8fe9b94c3Tadashi G. Takaoka            final Rect bounds = new Rect();
272c9f562a9a4c2b634eb43d1ddaef69068c0d93f6fKen Wakasa            paint.getTextBounds(MORE_SUGGESTIONS_HINT, 0, MORE_SUGGESTIONS_HINT.length(), bounds);
2730967ef40368c4bc7a0576ecc3dc222a8fe9b94c3Tadashi G. Takaoka            final int width = Math.round(bounds.width() + 0.5f);
2740967ef40368c4bc7a0576ecc3dc222a8fe9b94c3Tadashi G. Takaoka            final int height = Math.round(bounds.height() + 0.5f);
2750967ef40368c4bc7a0576ecc3dc222a8fe9b94c3Tadashi G. Takaoka            final Bitmap buffer = Bitmap.createBitmap(
2760967ef40368c4bc7a0576ecc3dc222a8fe9b94c3Tadashi G. Takaoka                    width, (height * 3 / 2), Bitmap.Config.ARGB_8888);
2770967ef40368c4bc7a0576ecc3dc222a8fe9b94c3Tadashi G. Takaoka            final Canvas canvas = new Canvas(buffer);
2780967ef40368c4bc7a0576ecc3dc222a8fe9b94c3Tadashi G. Takaoka            canvas.drawText(MORE_SUGGESTIONS_HINT, width / 2, height, paint);
2790967ef40368c4bc7a0576ecc3dc222a8fe9b94c3Tadashi G. Takaoka            return new BitmapDrawable(res, buffer);
2800967ef40368c4bc7a0576ecc3dc222a8fe9b94c3Tadashi G. Takaoka        }
2810967ef40368c4bc7a0576ecc3dc222a8fe9b94c3Tadashi G. Takaoka
282e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka        private CharSequence getStyledSuggestionWord(SuggestedWords suggestedWords, int pos) {
283e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka            final CharSequence word = suggestedWords.getWord(pos);
284e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka            final boolean isAutoCorrect = pos == 1 && suggestedWords.willAutoCorrect();
285e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka            final boolean isTypedWordValid = pos == 0 && suggestedWords.mTypedWordValid;
286d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka            if (!isAutoCorrect && !isTypedWordValid)
287d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka                return word;
288d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka
289d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            final int len = word.length();
290d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            final Spannable spannedWord = new SpannableString(word);
291d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka            final int option = mSuggestionStripOption;
292d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka            if ((isAutoCorrect && (option & AUTO_CORRECT_BOLD) != 0)
293d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka                    || (isTypedWordValid && (option & VALID_TYPED_WORD_BOLD) != 0)) {
294d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka                spannedWord.setSpan(BOLD_SPAN, 0, len, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
295d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka            }
296d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka            if (isAutoCorrect && (option & AUTO_CORRECT_UNDERLINE) != 0) {
297d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka                spannedWord.setSpan(UNDERLINE_SPAN, 0, len, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
298d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka            }
299d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            return spannedWord;
300d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        }
301d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka
302e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka        private int getWordPosition(int index, SuggestedWords suggestedWords) {
30360a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            // TODO: This works for 3 suggestions. Revisit this algorithm when there are 5 or more
30460a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            // suggestions.
305e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka            final int centerPos = suggestedWords.willAutoCorrect() ? 1 : 0;
306913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka            if (index == mCenterSuggestionIndex) {
30760a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                return centerPos;
30860a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            } else if (index == centerPos) {
309913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka                return mCenterSuggestionIndex;
31060a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            } else {
311d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka                return index;
312d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            }
313d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        }
314d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka
315e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka        private int getSuggestionTextColor(int index, SuggestedWords suggestedWords, int pos) {
316d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            // TODO: Need to revisit this logic with bigram suggestions
317913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka            final boolean isSuggested = (pos != 0);
318d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka
319d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            final int color;
320e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka            if (index == mCenterSuggestionIndex && suggestedWords.willAutoCorrect()) {
321d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka                color = mColorAutoCorrect;
322e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka            } else if (index == mCenterSuggestionIndex && suggestedWords.mTypedWordValid) {
323a44685ab326809185a0e4c44afabe8fd93441b4cTadashi G. Takaoka                color = mColorValidTypedWord;
324913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka            } else if (isSuggested) {
325913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka                color = mColorSuggested;
326d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            } else {
327d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka                color = mColorTypedWord;
328d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            }
329c0c20b386fb06b688f56dd7f807e2bcbb70b3a59Jean Chalard            if (LatinImeLogger.sDBG && suggestedWords.size() > 1) {
330ebbb7e9665b2f9bce46ddc2daa82b9ef73f6c712Jean Chalard                // If we auto-correct, then the autocorrection is in slot 0 and the typed word
331ebbb7e9665b2f9bce46ddc2daa82b9ef73f6c712Jean Chalard                // is in slot 1.
332f72b8f5662afb42b08eb88e92731d52f99df13e3Jean Chalard                if (index == mCenterSuggestionIndex
333f72b8f5662afb42b08eb88e92731d52f99df13e3Jean Chalard                        && AutoCorrection.shouldBlockAutoCorrectionBySafetyNet(
334f72b8f5662afb42b08eb88e92731d52f99df13e3Jean Chalard                                suggestedWords.getWord(1).toString(), suggestedWords.getWord(0))) {
3352aa1dd45c44295e2f7e8ece1b520032d86b9f908satok                    return 0xFFFF0000;
3362aa1dd45c44295e2f7e8ece1b520032d86b9f908satok                }
3372aa1dd45c44295e2f7e8ece1b520032d86b9f908satok            }
33860a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka
3394f6cf258fe208329247ade7a6701ac9709820717Jean Chalard            if (suggestedWords.mIsObsoleteSuggestions && isSuggested) {
340697bf585f8dac6ffc4d008c02b63407cfdd83104Tadashi G. Takaoka                return applyAlpha(color, mAlphaObsoleted);
341d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            } else {
342d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka                return color;
343d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            }
344d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        }
345d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka
346d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        private static int applyAlpha(final int color, final float alpha) {
347d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            final int newAlpha = (int)(Color.alpha(color) * alpha);
348d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            return Color.argb(newAlpha, Color.red(color), Color.green(color), Color.blue(color));
349d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        }
350d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka
3512c47080e7b4b9b2a6c2dbf1444e041c1b7943316Tadashi G. Takaoka        private static void addDivider(final ViewGroup stripView, final View divider) {
3522c47080e7b4b9b2a6c2dbf1444e041c1b7943316Tadashi G. Takaoka            stripView.addView(divider);
3532c47080e7b4b9b2a6c2dbf1444e041c1b7943316Tadashi G. Takaoka            final LinearLayout.LayoutParams params =
3542c47080e7b4b9b2a6c2dbf1444e041c1b7943316Tadashi G. Takaoka                    (LinearLayout.LayoutParams)divider.getLayoutParams();
3552c47080e7b4b9b2a6c2dbf1444e041c1b7943316Tadashi G. Takaoka            params.gravity = Gravity.CENTER;
3562c47080e7b4b9b2a6c2dbf1444e041c1b7943316Tadashi G. Takaoka        }
3572c47080e7b4b9b2a6c2dbf1444e041c1b7943316Tadashi G. Takaoka
358e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka        public void layout(SuggestedWords suggestedWords, ViewGroup stripView, ViewGroup placer,
35916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                int stripWidth) {
360e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka            if (suggestedWords.mIsPunctuationSuggestions) {
361e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka                layoutPunctuationSuggestions(suggestedWords, stripView);
3623a566c48b0eb3625788e1cce3fb2f58d8f4b380dTadashi G. Takaoka                return;
36360a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            }
36460a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka
365913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka            final int countInStrip = mSuggestionsCountInStrip;
366e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka            setupTexts(suggestedWords, countInStrip);
367e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka            mMoreSuggestionsAvailable = (suggestedWords.size() > countInStrip);
36860a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            int x = 0;
36960a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            for (int index = 0; index < countInStrip; index++) {
370e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka                final int pos = getWordPosition(index, suggestedWords);
37160a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka
37260a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                if (index != 0) {
37360a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                    final View divider = mDividers.get(pos);
374913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka                    // Add divider if this isn't the left most suggestion in suggestions strip.
3752c47080e7b4b9b2a6c2dbf1444e041c1b7943316Tadashi G. Takaoka                    addDivider(stripView, divider);
376013ba3e3e785980b74db83ac5ab1e11b438485daTadashi G. Takaoka                    x += divider.getMeasuredWidth();
37760a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                }
37860a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka
37916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                final CharSequence styled = mTexts.get(pos);
38060a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                final TextView word = mWords.get(pos);
381913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka                if (index == mCenterSuggestionIndex && mMoreSuggestionsAvailable) {
382ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka                    // TODO: This "more suggestions hint" should have nicely designed icon.
383ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka                    word.setCompoundDrawablesWithIntrinsicBounds(
384913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka                            null, null, null, mMoreSuggestionsHint);
385580e1d7ac0cb90a464a3b3aed88047f85a4ab41fTadashi G. Takaoka                    // HACK: To align with other TextView that has no compound drawables.
386913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka                    word.setCompoundDrawablePadding(-mMoreSuggestionsHint.getIntrinsicHeight());
387ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka                } else {
388580e1d7ac0cb90a464a3b3aed88047f85a4ab41fTadashi G. Takaoka                    word.setCompoundDrawablesWithIntrinsicBounds(null, null, null, null);
389ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka                }
390ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka
391913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka                // Disable this suggestion if the suggestion is null or empty.
39260a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                word.setEnabled(!TextUtils.isEmpty(styled));
393e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka                word.setTextColor(getSuggestionTextColor(index, suggestedWords, pos));
394913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka                final int width = getSuggestionWidth(index, stripWidth);
39560a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                final CharSequence text = getEllipsizedText(styled, width, word.getPaint());
39660a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                final float scaleX = word.getTextScaleX();
39760a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                word.setText(text); // TextView.setText() resets text scale x to 1.0.
39860a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                word.setTextScaleX(scaleX);
39960a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                stripView.addView(word);
400b8dc67466339dc14653ad634c86851025373326bTadashi G. Takaoka                setLayoutWeight(
401913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka                        word, getSuggestionWeight(index), ViewGroup.LayoutParams.MATCH_PARENT);
402013ba3e3e785980b74db83ac5ab1e11b438485daTadashi G. Takaoka                x += word.getMeasuredWidth();
40316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka
404042557b45bf2554608cd22874633011157cd1752Jean Chalard                if (DBG && pos < suggestedWords.size()) {
405042557b45bf2554608cd22874633011157cd1752Jean Chalard                    final CharSequence debugInfo = Utils.getDebugInfo(suggestedWords, pos);
40616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    if (debugInfo != null) {
40760a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                        final TextView info = mInfos.get(pos);
40816713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                        info.setText(debugInfo);
409013ba3e3e785980b74db83ac5ab1e11b438485daTadashi G. Takaoka                        placer.addView(info);
410b8dc67466339dc14653ad634c86851025373326bTadashi G. Takaoka                        info.measure(ViewGroup.LayoutParams.WRAP_CONTENT,
411b8dc67466339dc14653ad634c86851025373326bTadashi G. Takaoka                                ViewGroup.LayoutParams.WRAP_CONTENT);
41260a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                        final int infoWidth = info.getMeasuredWidth();
41316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                        final int y = info.getMeasuredHeight();
414c8461d1ae26d43a09c0f835d833f3d49fbe8d2f3Tadashi G. Takaoka                        ViewLayoutUtils.placeViewAt(
415013ba3e3e785980b74db83ac5ab1e11b438485daTadashi G. Takaoka                                info, x - infoWidth, y, infoWidth, info.getMeasuredHeight());
41616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    }
41760a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                }
41816713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka            }
41916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka        }
42016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka
421913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka        private int getSuggestionWidth(int index, int maxWidth) {
422913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka            final int paddings = mPadding * mSuggestionsCountInStrip;
423913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka            final int dividers = mDividerWidth * (mSuggestionsCountInStrip - 1);
42460a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            final int availableWidth = maxWidth - paddings - dividers;
425913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka            return (int)(availableWidth * getSuggestionWeight(index));
42660a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka        }
42774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
428913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka        private float getSuggestionWeight(int index) {
429913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka            if (index == mCenterSuggestionIndex) {
430913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka                return mCenterSuggestionWeight;
43160a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            } else {
43260a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                // TODO: Revisit this for cases of 5 or more suggestions
433913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka                return (1.0f - mCenterSuggestionWeight) / (mSuggestionsCountInStrip - 1);
43474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            }
43574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        }
43674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
437e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka        private void setupTexts(SuggestedWords suggestedWords, int countInStrip) {
43874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            mTexts.clear();
439e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka            final int count = Math.min(suggestedWords.size(), countInStrip);
44060a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            for (int pos = 0; pos < count; pos++) {
441e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka                final CharSequence styled = getStyledSuggestionWord(suggestedWords, pos);
44274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                mTexts.add(styled);
44374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            }
44460a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            for (int pos = count; pos < countInStrip; pos++) {
44560a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                // Make this inactive for touches in layout().
44660a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                mTexts.add(null);
44760a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            }
44874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        }
44974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
450e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka        private void layoutPunctuationSuggestions(SuggestedWords suggestedWords,
451e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka                ViewGroup stripView) {
452e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka            final int countInStrip = Math.min(suggestedWords.size(), PUNCTUATIONS_IN_STRIP);
45360a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            for (int index = 0; index < countInStrip; index++) {
45460a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                if (index != 0) {
455913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka                    // Add divider if this isn't the left most suggestion in suggestions strip.
4562c47080e7b4b9b2a6c2dbf1444e041c1b7943316Tadashi G. Takaoka                    addDivider(stripView, mDividers.get(index));
45760a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                }
45860a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka
45960a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                final TextView word = mWords.get(index);
46060a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                word.setEnabled(true);
461a44685ab326809185a0e4c44afabe8fd93441b4cTadashi G. Takaoka                word.setTextColor(mColorAutoCorrect);
462e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka                final CharSequence text = suggestedWords.getWord(index);
46360a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                word.setText(text);
46460a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                word.setTextScaleX(1.0f);
465ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka                word.setCompoundDrawables(null, null, null, null);
46660a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                stripView.addView(word);
467913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka                setLayoutWeight(word, 1.0f, mSuggestionsStripHeight);
46860a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            }
469ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka            mMoreSuggestionsAvailable = false;
47074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        }
471c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka
472c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka        public void layoutAddToDictionaryHint(CharSequence word, ViewGroup stripView,
4739f763d14451685965039990891eb0bc8e8db0735Tadashi G. Takaoka                int stripWidth, CharSequence hintText, OnClickListener listener) {
474c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            final int width = stripWidth - mDividerWidth - mPadding * 2;
475c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka
476c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            final TextView wordView = mWordToSaveView;
477c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            wordView.setTextColor(mColorTypedWord);
478913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka            final int wordWidth = (int)(width * mCenterSuggestionWeight);
479c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            final CharSequence text = getEllipsizedText(word, wordWidth, wordView.getPaint());
480c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            final float wordScaleX = wordView.getTextScaleX();
481c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            wordView.setTag(word);
482c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            wordView.setText(text);
483c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            wordView.setTextScaleX(wordScaleX);
484c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            stripView.addView(wordView);
485913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka            setLayoutWeight(wordView, mCenterSuggestionWeight, ViewGroup.LayoutParams.MATCH_PARENT);
486c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka
487c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            stripView.addView(mDividers.get(0));
488c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka
4892eb8781dc2e42d55474fb6e5c461c56c066b8363Tadashi G. Takaoka            final TextView leftArrowView = mLeftwardsArrowView;
4902eb8781dc2e42d55474fb6e5c461c56c066b8363Tadashi G. Takaoka            leftArrowView.setTextColor(mColorAutoCorrect);
4912eb8781dc2e42d55474fb6e5c461c56c066b8363Tadashi G. Takaoka            leftArrowView.setText(LEFTWARDS_ARROW);
4922eb8781dc2e42d55474fb6e5c461c56c066b8363Tadashi G. Takaoka            stripView.addView(leftArrowView);
4932eb8781dc2e42d55474fb6e5c461c56c066b8363Tadashi G. Takaoka
494c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            final TextView hintView = mHintToSaveView;
4952eb8781dc2e42d55474fb6e5c461c56c066b8363Tadashi G. Takaoka            hintView.setGravity(Gravity.LEFT | Gravity.CENTER_VERTICAL);
496c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            hintView.setTextColor(mColorAutoCorrect);
4972eb8781dc2e42d55474fb6e5c461c56c066b8363Tadashi G. Takaoka            final int hintWidth = width - wordWidth - leftArrowView.getWidth();
498644d33d60ea5a87501274488013d65f55238895eKen Wakasa            final float hintScaleX = getTextScaleX(hintText, hintWidth, hintView.getPaint());
499644d33d60ea5a87501274488013d65f55238895eKen Wakasa            hintView.setText(hintText);
500c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            hintView.setTextScaleX(hintScaleX);
501c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            stripView.addView(hintView);
502b8dc67466339dc14653ad634c86851025373326bTadashi G. Takaoka            setLayoutWeight(
503913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka                    hintView, 1.0f - mCenterSuggestionWeight, ViewGroup.LayoutParams.MATCH_PARENT);
5049f763d14451685965039990891eb0bc8e8db0735Tadashi G. Takaoka
5059f763d14451685965039990891eb0bc8e8db0735Tadashi G. Takaoka            wordView.setOnClickListener(listener);
5069f763d14451685965039990891eb0bc8e8db0735Tadashi G. Takaoka            leftArrowView.setOnClickListener(listener);
5079f763d14451685965039990891eb0bc8e8db0735Tadashi G. Takaoka            hintView.setOnClickListener(listener);
5089f763d14451685965039990891eb0bc8e8db0735Tadashi G. Takaoka        }
5099f763d14451685965039990891eb0bc8e8db0735Tadashi G. Takaoka
5109f763d14451685965039990891eb0bc8e8db0735Tadashi G. Takaoka        public CharSequence getAddToDictionaryWord() {
5119f763d14451685965039990891eb0bc8e8db0735Tadashi G. Takaoka            return (CharSequence)mWordToSaveView.getTag();
5129f763d14451685965039990891eb0bc8e8db0735Tadashi G. Takaoka        }
5139f763d14451685965039990891eb0bc8e8db0735Tadashi G. Takaoka
5149f763d14451685965039990891eb0bc8e8db0735Tadashi G. Takaoka        public boolean isAddToDictionaryShowing(View v) {
5159f763d14451685965039990891eb0bc8e8db0735Tadashi G. Takaoka            return v == mWordToSaveView || v == mHintToSaveView || v == mLeftwardsArrowView;
516c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka        }
5172d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka
5182d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka        private static void setLayoutWeight(View v, float weight, int height) {
5192d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka            final ViewGroup.LayoutParams lp = v.getLayoutParams();
5202d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka            if (lp instanceof LinearLayout.LayoutParams) {
5212d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka                final LinearLayout.LayoutParams llp = (LinearLayout.LayoutParams)lp;
5222d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka                llp.weight = weight;
5232d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka                llp.width = 0;
5242d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka                llp.height = height;
5252d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka            }
5262d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka        }
5272d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka
5282d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka        private static float getTextScaleX(CharSequence text, int maxWidth, TextPaint paint) {
5292d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka            paint.setTextScaleX(1.0f);
5302d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka            final int width = getTextWidth(text, paint);
5312d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka            if (width <= maxWidth) {
5322d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka                return 1.0f;
5332d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka            }
5342d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka            return maxWidth / (float)width;
5352d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka        }
5362d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka
5372d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka        private static CharSequence getEllipsizedText(CharSequence text, int maxWidth,
5382d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka                TextPaint paint) {
5392d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka            if (text == null) return null;
5402d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka            paint.setTextScaleX(1.0f);
5412d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka            final int width = getTextWidth(text, paint);
5422d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka            if (width <= maxWidth) {
5432d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka                return text;
5442d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka            }
5452d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka            final float scaleX = maxWidth / (float)width;
5462d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka            if (scaleX >= MIN_TEXT_XSCALE) {
5472d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka                paint.setTextScaleX(scaleX);
5482d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka                return text;
5492d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka            }
5502d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka
5512d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka            // Note that TextUtils.ellipsize() use text-x-scale as 1.0 if ellipsize is needed. To
5522d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka            // get squeezed and ellipsized text, passes enlarged width (maxWidth / MIN_TEXT_XSCALE).
5532d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka            final CharSequence ellipsized = TextUtils.ellipsize(
5542d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka                    text, paint, maxWidth / MIN_TEXT_XSCALE, TextUtils.TruncateAt.MIDDLE);
5552d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka            paint.setTextScaleX(MIN_TEXT_XSCALE);
5562d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka            return ellipsized;
5572d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka        }
5582d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka
5592d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka        private static int getTextWidth(CharSequence text, TextPaint paint) {
5602d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka            if (TextUtils.isEmpty(text)) return 0;
5612d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka            final Typeface savedTypeface = paint.getTypeface();
5622d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka            paint.setTypeface(getTextTypeface(text));
5632d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka            final int len = text.length();
5642d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka            final float[] widths = new float[len];
5652d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka            final int count = paint.getTextWidths(text, 0, len, widths);
5662d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka            int width = 0;
5672d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka            for (int i = 0; i < count; i++) {
5682d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka                width += Math.round(widths[i] + 0.5f);
5692d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka            }
5702d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka            paint.setTypeface(savedTypeface);
5712d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka            return width;
5722d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka        }
5732d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka
5742d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka        private static Typeface getTextTypeface(CharSequence text) {
5752d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka            if (!(text instanceof SpannableString))
5762d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka                return Typeface.DEFAULT;
5772d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka
5782d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka            final SpannableString ss = (SpannableString)text;
5792d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka            final StyleSpan[] styles = ss.getSpans(0, text.length(), StyleSpan.class);
5802d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka            if (styles.length == 0)
5812d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka                return Typeface.DEFAULT;
5822d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka
5832d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka            switch (styles[0].getStyle()) {
5842d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka            case Typeface.BOLD: return Typeface.DEFAULT_BOLD;
5852d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka            // TODO: BOLD_ITALIC, ITALIC case?
5862d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka            default: return Typeface.DEFAULT;
5872d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka            }
5882d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka        }
58974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka    }
59074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
591923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    /**
5924702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka     * Construct a {@link SuggestionStripView} for showing suggestions to be picked by the user.
593923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     * @param context
594923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     * @param attrs
595923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     */
5964702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka    public SuggestionStripView(Context context, AttributeSet attrs) {
5974702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka        this(context, attrs, R.attr.suggestionStripViewStyle);
59808a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka    }
59908a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka
6004702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka    public SuggestionStripView(Context context, AttributeSet attrs, int defStyle) {
601c412309b7a32308b1b0a175dafc13f90254353c5Tadashi G. Takaoka        super(context, attrs, defStyle);
602923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
60316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka        final LayoutInflater inflater = LayoutInflater.from(context);
604913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka        inflater.inflate(R.layout.suggestions_strip, this);
60586e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka
60686e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        mPreviewPopup = new PopupWindow(context);
607913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka        mPreviewText = (TextView) inflater.inflate(R.layout.suggestion_preview, null);
608b8dc67466339dc14653ad634c86851025373326bTadashi G. Takaoka        mPreviewPopup.setWindowLayoutMode(
609b8dc67466339dc14653ad634c86851025373326bTadashi G. Takaoka                ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
610923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mPreviewPopup.setContentView(mPreviewText);
611923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mPreviewPopup.setBackgroundDrawable(null);
612923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
613913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka        mSuggestionsStrip = (ViewGroup)findViewById(R.id.suggestions_strip);
61460a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka        for (int pos = 0; pos < MAX_SUGGESTIONS; pos++) {
615913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka            final TextView word = (TextView)inflater.inflate(R.layout.suggestion_word, null);
61660a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            word.setTag(pos);
6172442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka            word.setOnClickListener(this);
618ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka            word.setOnLongClickListener(this);
6192442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka            mWords.add(word);
620913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka            final View divider = inflater.inflate(R.layout.suggestion_divider, null);
62160a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            divider.setTag(pos);
622a1aab83a24e74cb0fad4b1c1e59b18d23ecbdad3Tadashi G. Takaoka            divider.setOnClickListener(this);
623a1aab83a24e74cb0fad4b1c1e59b18d23ecbdad3Tadashi G. Takaoka            mDividers.add(divider);
624913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka            mInfos.add((TextView)inflater.inflate(R.layout.suggestion_info, null));
625c9716b28ce438e06b5cacc07fc002944bcbe24a0Tadashi G. Takaoka        }
626179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaoka
6274702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka        mParams = new SuggestionStripViewParams(
6284702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka                context, attrs, defStyle, mWords, mDividers, mInfos);
62929e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka
63029e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka        mMoreSuggestionsContainer = inflater.inflate(R.layout.more_suggestions, null);
63129e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka        mMoreSuggestionsView = (MoreSuggestionsView)mMoreSuggestionsContainer
63229e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka                .findViewById(R.id.more_suggestions_view);
63329e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka        mMoreSuggestionsBuilder = new MoreSuggestions.Builder(mMoreSuggestionsView);
634bfc1d732ac92fa1bd5b19ad9e7c71ce9a1f9dc00Tadashi G. Takaoka
635bfc1d732ac92fa1bd5b19ad9e7c71ce9a1f9dc00Tadashi G. Takaoka        final PopupWindow moreWindow = new PopupWindow(context);
636bfc1d732ac92fa1bd5b19ad9e7c71ce9a1f9dc00Tadashi G. Takaoka        moreWindow.setWindowLayoutMode(
63729e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka                ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
638bfc1d732ac92fa1bd5b19ad9e7c71ce9a1f9dc00Tadashi G. Takaoka        moreWindow.setBackgroundDrawable(new ColorDrawable(android.R.color.transparent));
639bfc1d732ac92fa1bd5b19ad9e7c71ce9a1f9dc00Tadashi G. Takaoka        moreWindow.setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED);
640bfc1d732ac92fa1bd5b19ad9e7c71ce9a1f9dc00Tadashi G. Takaoka        moreWindow.setFocusable(true);
641bfc1d732ac92fa1bd5b19ad9e7c71ce9a1f9dc00Tadashi G. Takaoka        moreWindow.setOutsideTouchable(true);
642bfc1d732ac92fa1bd5b19ad9e7c71ce9a1f9dc00Tadashi G. Takaoka        moreWindow.setOnDismissListener(new PopupWindow.OnDismissListener() {
643bfc1d732ac92fa1bd5b19ad9e7c71ce9a1f9dc00Tadashi G. Takaoka            @Override
644bfc1d732ac92fa1bd5b19ad9e7c71ce9a1f9dc00Tadashi G. Takaoka            public void onDismiss() {
645bfc1d732ac92fa1bd5b19ad9e7c71ce9a1f9dc00Tadashi G. Takaoka                mKeyboardView.dimEntireKeyboard(false);
646bfc1d732ac92fa1bd5b19ad9e7c71ce9a1f9dc00Tadashi G. Takaoka            }
647bfc1d732ac92fa1bd5b19ad9e7c71ce9a1f9dc00Tadashi G. Takaoka        });
648bfc1d732ac92fa1bd5b19ad9e7c71ce9a1f9dc00Tadashi G. Takaoka        mMoreSuggestionsWindow = moreWindow;
649bfc1d732ac92fa1bd5b19ad9e7c71ce9a1f9dc00Tadashi G. Takaoka
65050e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka        final Resources res = context.getResources();
65150e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka        mMoreSuggestionsModalTolerance = res.getDimensionPixelOffset(
65250e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka                R.dimen.more_suggestions_modal_tolerance);
6533fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka        mMoreSuggestionsSlidingDetector = new GestureDetector(
6543fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka                context, mMoreSuggestionsSlidingListener);
655923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
656c9716b28ce438e06b5cacc07fc002944bcbe24a0Tadashi G. Takaoka
657923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    /**
658c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka     * A connection back to the input method.
659923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     * @param listener
660923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     */
66186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka    public void setListener(Listener listener, View inputView) {
662c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka        mListener = listener;
6631b087064c07975c5e2b9c17d4ca80c56e01c35c0Tadashi G. Takaoka        mKeyboardView = (KeyboardView)inputView.findViewById(R.id.keyboard_view);
664923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
665923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
666e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka    public void setSuggestions(SuggestedWords suggestedWords) {
667d5b765b3bbceb80b2e145ac7f4d66acbadd1ee4fJean Chalard        if (suggestedWords == null)
668a15e45ef45931ba46678b39c159518d8aa2d4d65Tadashi G. Takaoka            return;
66955b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka
670e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        clear();
671e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka        mSuggestedWords = suggestedWords;
672e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka        mParams.layout(mSuggestedWords, mSuggestionsStrip, this, getWidth());
673a9ca7867b5a7c0be115966211a05f5d460c8638cKurt Partridge        if (ProductionFlag.IS_EXPERIMENTAL) {
6744702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka            ResearchLogger.suggestionStripView_setSuggestions(mSuggestedWords);
675a9ca7867b5a7c0be115966211a05f5d460c8638cKurt Partridge        }
67616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka    }
67774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
678c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka    public int setMoreSuggestionsHeight(int remainingHeight) {
679c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka        return mParams.setMoreSuggestionsHeight(remainingHeight);
680c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka    }
681b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka
682b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani    public boolean isShowingAddToDictionaryHint() {
683913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka        return mSuggestionsStrip.getChildCount() > 0
6849f763d14451685965039990891eb0bc8e8db0735Tadashi G. Takaoka                && mParams.isAddToDictionaryShowing(mSuggestionsStrip.getChildAt(0));
685b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani    }
686b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani
687644d33d60ea5a87501274488013d65f55238895eKen Wakasa    public void showAddToDictionaryHint(CharSequence word, CharSequence hintText) {
688c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka        clear();
6899f763d14451685965039990891eb0bc8e8db0735Tadashi G. Takaoka        mParams.layoutAddToDictionaryHint(word, mSuggestionsStrip, getWidth(), hintText, this);
69066a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani    }
69166a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani
6926558253160e2039c87f424bd814f402ecd31de3bKen Wakasa    public boolean dismissAddToDictionaryHint() {
693c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka        if (isShowingAddToDictionaryHint()) {
694c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            clear();
695c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            return true;
696c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka        }
697c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka        return false;
6986558253160e2039c87f424bd814f402ecd31de3bKen Wakasa    }
6996558253160e2039c87f424bd814f402ecd31de3bKen Wakasa
7007e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka    public SuggestedWords getSuggestions() {
701e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka        return mSuggestedWords;
702979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
703979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
704923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void clear() {
705913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka        mSuggestionsStrip.removeAllViews();
706c412309b7a32308b1b0a175dafc13f90254353c5Tadashi G. Takaoka        removeAllViews();
707c412309b7a32308b1b0a175dafc13f90254353c5Tadashi G. Takaoka        addView(mSuggestionsStrip);
7081b087064c07975c5e2b9c17d4ca80c56e01c35c0Tadashi G. Takaoka        dismissMoreSuggestions();
709923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
710923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
7116ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani    private void hidePreview() {
712179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaoka        mPreviewPopup.dismiss();
7136ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani    }
714e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka
71529e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka    private final KeyboardActionListener mMoreSuggestionsListener =
71629e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka            new KeyboardActionListener.Adapter() {
71729e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka        @Override
71829e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka        public boolean onCustomRequest(int requestCode) {
71929e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka            final int index = requestCode;
720e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka            final CharSequence word = mSuggestedWords.getWord(index);
7216785b9072762e15bb49657ce7b7d228dab76e44aTadashi G. Takaoka            mListener.pickSuggestionManually(index, word);
7221b087064c07975c5e2b9c17d4ca80c56e01c35c0Tadashi G. Takaoka            dismissMoreSuggestions();
72329e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka            return true;
72429e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka        }
72529e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka
72629e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka        @Override
72729e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka        public void onCancelInput() {
7281b087064c07975c5e2b9c17d4ca80c56e01c35c0Tadashi G. Takaoka            dismissMoreSuggestions();
72929e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka        }
73029e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka    };
73129e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka
73229e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka    private final MoreKeysPanel.Controller mMoreSuggestionsController =
73329e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka            new MoreKeysPanel.Controller() {
73429e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka        @Override
73529e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka        public boolean dismissMoreKeysPanel() {
7361b087064c07975c5e2b9c17d4ca80c56e01c35c0Tadashi G. Takaoka            return dismissMoreSuggestions();
73729e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka        }
73829e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka    };
73929e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka
7401b087064c07975c5e2b9c17d4ca80c56e01c35c0Tadashi G. Takaoka    private boolean dismissMoreSuggestions() {
7411b087064c07975c5e2b9c17d4ca80c56e01c35c0Tadashi G. Takaoka        if (mMoreSuggestionsWindow.isShowing()) {
7421b087064c07975c5e2b9c17d4ca80c56e01c35c0Tadashi G. Takaoka            mMoreSuggestionsWindow.dismiss();
7431b087064c07975c5e2b9c17d4ca80c56e01c35c0Tadashi G. Takaoka            return true;
7441b087064c07975c5e2b9c17d4ca80c56e01c35c0Tadashi G. Takaoka        }
7451b087064c07975c5e2b9c17d4ca80c56e01c35c0Tadashi G. Takaoka        return false;
7461b087064c07975c5e2b9c17d4ca80c56e01c35c0Tadashi G. Takaoka    }
7471b087064c07975c5e2b9c17d4ca80c56e01c35c0Tadashi G. Takaoka
748e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka    @Override
749ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka    public boolean onLongClick(View view) {
7503fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka        return showMoreSuggestions();
7513fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka    }
7523fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka
7533fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka    private boolean showMoreSuggestions() {
7544702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka        final SuggestionStripViewParams params = mParams;
75529e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka        if (params.mMoreSuggestionsAvailable) {
75629e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka            final int stripWidth = getWidth();
75729e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka            final View container = mMoreSuggestionsContainer;
75829e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka            final int maxWidth = stripWidth - container.getPaddingLeft()
75929e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka                    - container.getPaddingRight();
76029e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka            final MoreSuggestions.Builder builder = mMoreSuggestionsBuilder;
761e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka            builder.layout(mSuggestedWords, params.mSuggestionsCountInStrip, maxWidth,
7629676038b6e9fb66760588d7f9c9c642cc493dd71Tadashi G. Takaoka                    (int)(maxWidth * params.mMinMoreSuggestionsWidth),
763c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka                    params.getMaxMoreSuggestionsRow());
76429e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka            mMoreSuggestionsView.setKeyboard(builder.build());
76529e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka            container.measure(
76629e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka                    ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
76729e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka
76829e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka            final MoreKeysPanel moreKeysPanel = mMoreSuggestionsView;
76929e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka            final int pointX = stripWidth / 2;
7704269a7cebdfe5c76372d0f0dd187432f0594ffe5Tadashi G. Takaoka            final int pointY = -params.mMoreSuggestionsBottomGap;
77129e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka            moreKeysPanel.showMoreKeysPanel(
77229e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka                    this, mMoreSuggestionsController, pointX, pointY,
77329e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka                    mMoreSuggestionsWindow, mMoreSuggestionsListener);
774d7b00f34904c61f955e439160e2dbaa3a4b6983cTadashi G. Takaoka            mMoreSuggestionsMode = MORE_SUGGESTIONS_CHECKING_MODAL_OR_SLIDING;
77550e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka            mOriginX = mLastX;
77650e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka            mOriginY = mLastY;
7771b087064c07975c5e2b9c17d4ca80c56e01c35c0Tadashi G. Takaoka            mKeyboardView.dimEntireKeyboard(true);
7783fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka            for (int i = 0; i < params.mSuggestionsCountInStrip; i++) {
7793fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka                mWords.get(i).setPressed(false);
7803fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka            }
781ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka            return true;
782ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka        }
783ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka        return false;
784ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka    }
785ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka
78650e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka    // Working variables for onLongClick and dispatchTouchEvent.
787d7b00f34904c61f955e439160e2dbaa3a4b6983cTadashi G. Takaoka    private int mMoreSuggestionsMode = MORE_SUGGESTIONS_IN_MODAL_MODE;
788d7b00f34904c61f955e439160e2dbaa3a4b6983cTadashi G. Takaoka    private static final int MORE_SUGGESTIONS_IN_MODAL_MODE = 0;
789d7b00f34904c61f955e439160e2dbaa3a4b6983cTadashi G. Takaoka    private static final int MORE_SUGGESTIONS_CHECKING_MODAL_OR_SLIDING = 1;
790d7b00f34904c61f955e439160e2dbaa3a4b6983cTadashi G. Takaoka    private static final int MORE_SUGGESTIONS_IN_SLIDING_MODE = 2;
79150e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka    private int mLastX;
79250e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka    private int mLastY;
79350e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka    private int mOriginX;
79450e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka    private int mOriginY;
79550e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka    private final int mMoreSuggestionsModalTolerance;
7963fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka    private final GestureDetector mMoreSuggestionsSlidingDetector;
7973fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka    private final GestureDetector.OnGestureListener mMoreSuggestionsSlidingListener =
7983fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka            new GestureDetector.SimpleOnGestureListener() {
7993fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka        @Override
8003fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka        public boolean onScroll(MotionEvent down, MotionEvent me, float deltaX, float deltaY) {
8013fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka            final float dy = me.getY() - down.getY();
8023fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka            if (deltaY > 0 && dy < 0) {
8033fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka                return showMoreSuggestions();
8043fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka            }
8053fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka            return false;
8063fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka        }
8073fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka    };
80850e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka
809ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka    @Override
81029e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka    public boolean dispatchTouchEvent(MotionEvent me) {
811d7b00f34904c61f955e439160e2dbaa3a4b6983cTadashi G. Takaoka        if (!mMoreSuggestionsWindow.isShowing()
812d7b00f34904c61f955e439160e2dbaa3a4b6983cTadashi G. Takaoka                || mMoreSuggestionsMode == MORE_SUGGESTIONS_IN_MODAL_MODE) {
81350e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka            mLastX = (int)me.getX();
81450e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka            mLastY = (int)me.getY();
8153fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka            if (mMoreSuggestionsSlidingDetector.onTouchEvent(me)) {
8163fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka                return true;
8173fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka            }
81829e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka            return super.dispatchTouchEvent(me);
81929e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka        }
8208ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka
8218ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka        final MoreKeysPanel moreKeysPanel = mMoreSuggestionsView;
82229e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka        final int action = me.getAction();
82329e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka        final long eventTime = me.getEventTime();
82429e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka        final int index = me.getActionIndex();
82529e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka        final int id = me.getPointerId(index);
8268ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka        final PointerTracker tracker = PointerTracker.getPointerTracker(id, moreKeysPanel);
8278ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka        final int x = (int)me.getX(index);
8288ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka        final int y = (int)me.getY(index);
8298ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka        final int translatedX = moreKeysPanel.translateX(x);
8308ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka        final int translatedY = moreKeysPanel.translateY(y);
8318ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka
832d7b00f34904c61f955e439160e2dbaa3a4b6983cTadashi G. Takaoka        if (mMoreSuggestionsMode == MORE_SUGGESTIONS_CHECKING_MODAL_OR_SLIDING) {
83387104bace9cb9ed1a700f05a37743a21c2722fffTadashi G. Takaoka            if (Math.abs(x - mOriginX) >= mMoreSuggestionsModalTolerance
83487104bace9cb9ed1a700f05a37743a21c2722fffTadashi G. Takaoka                    || mOriginY - y >= mMoreSuggestionsModalTolerance) {
83587104bace9cb9ed1a700f05a37743a21c2722fffTadashi G. Takaoka                // Decided to be in the sliding input mode only when the touch point has been moved
83687104bace9cb9ed1a700f05a37743a21c2722fffTadashi G. Takaoka                // upward.
837d7b00f34904c61f955e439160e2dbaa3a4b6983cTadashi G. Takaoka                mMoreSuggestionsMode = MORE_SUGGESTIONS_IN_SLIDING_MODE;
838e51d164482c7896892d6eccb80f1e1e6fe6d50dbTadashi G. Takaoka                tracker.onShowMoreKeysPanel(translatedX, translatedY, moreKeysPanel);
83950e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka            } else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_POINTER_UP) {
84050e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka                // Decided to be in the modal input mode
841d7b00f34904c61f955e439160e2dbaa3a4b6983cTadashi G. Takaoka                mMoreSuggestionsMode = MORE_SUGGESTIONS_IN_MODAL_MODE;
84250e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka            }
84350e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka            return true;
84450e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka        }
84550e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka
846d7b00f34904c61f955e439160e2dbaa3a4b6983cTadashi G. Takaoka        // MORE_SUGGESTIONS_IN_SLIDING_MODE
8478ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka        tracker.processMotionEvent(action, translatedX, translatedY, eventTime, moreKeysPanel);
84829e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka        return true;
84929e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka    }
85029e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka
85129e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka    @Override
852e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka    public void onClick(View view) {
8539f763d14451685965039990891eb0bc8e8db0735Tadashi G. Takaoka        if (mParams.isAddToDictionaryShowing(view)) {
8543d8e7a62fc6182c12ca28c29ceeee52ed4b9eea7Jean Chalard            mListener.addWordToUserDictionary(mParams.getAddToDictionaryWord().toString());
855717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka            clear();
856717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka            return;
857717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka        }
858717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka
85986e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        final Object tag = view.getTag();
86086e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        if (!(tag instanceof Integer))
86186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka            return;
86286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        final int index = (Integer) tag;
863e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka        if (index >= mSuggestedWords.size())
86437deb112c727dfed5e94d054cf5f00f5d60c8120Tadashi G. Takaoka            return;
86586e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka
866e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka        final CharSequence word = mSuggestedWords.getWord(index);
8676785b9072762e15bb49657ce7b7d228dab76e44aTadashi G. Takaoka        mListener.pickSuggestionManually(index, word);
868923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
86982411d47ba7e8133ed2390c6920945e139a738cesatok
8706ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani    @Override
87173cd4c1428ac370e1c15c5f61b1ce499f0d4f4c7Tadashi G. Takaoka    protected void onDetachedFromWindow() {
8726ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani        super.onDetachedFromWindow();
87355b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        mHandler.cancelAllMessages();
8746ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani        hidePreview();
87532f4ceb2434b6f204cf8152b406d0f9a642feb73Tadashi G. Takaoka        dismissMoreSuggestions();
8766ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani    }
877923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project}
878