SuggestionStripView.java revision 6f7905ae757c30ac0f8080f025b88afc61a6f6b1
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; 537339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaokaimport com.android.inputmethod.keyboard.KeyboardSwitcher; 54d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaokaimport com.android.inputmethod.keyboard.MainKeyboardView; 5529e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaokaimport com.android.inputmethod.keyboard.MoreKeysPanel; 56c8461d1ae26d43a09c0f835d833f3d49fbe8d2f3Tadashi G. Takaokaimport com.android.inputmethod.keyboard.ViewLayoutUtils; 57f72b8f5662afb42b08eb88e92731d52f99df13e3Jean Chalardimport com.android.inputmethod.latin.AutoCorrection; 585f282ea9e4a4590fcbab6e27d5fca7dacbb40a6aTadashi G. Takaokaimport com.android.inputmethod.latin.CollectionUtils; 595faf41951929301af80026bc3191812ef874fd5aTadashi G. Takaokaimport com.android.inputmethod.latin.Constants; 608c3d5b6961a9b9d40c4bf21ad495f852971c24f4Tadashi G. Takaokaimport com.android.inputmethod.latin.LatinImeLogger; 618c3d5b6961a9b9d40c4bf21ad495f852971c24f4Tadashi G. Takaokaimport com.android.inputmethod.latin.R; 6292821614fd80112527e133f069e31ee48250314fTadashi G. Takaokaimport com.android.inputmethod.latin.ResourceUtils; 638c3d5b6961a9b9d40c4bf21ad495f852971c24f4Tadashi G. Takaokaimport com.android.inputmethod.latin.SuggestedWords; 649310f42a36eabe99ed7dcd3b835d6cdaa3c6fdcaJean Chalardimport com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; 65042557b45bf2554608cd22874633011157cd1752Jean Chalardimport com.android.inputmethod.latin.Utils; 66a9ca7867b5a7c0be115966211a05f5d460c8638cKurt Partridgeimport com.android.inputmethod.latin.define.ProductionFlag; 676f7905ae757c30ac0f8080f025b88afc61a6f6b1Tadashi G. Takaokaimport com.android.inputmethod.latin.suggestions.MoreSuggestions.MoreSuggestionsListener; 686b966160ac8570271547bf63217efa5e228d4accKurt Partridgeimport com.android.inputmethod.research.ResearchLogger; 69ddb61ea461b920d87be4ad78c8a36eec1013b965Tadashi G. Takaoka 70179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaokaimport java.util.ArrayList; 71179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaoka 72a28a05e971cc242b338331a3b78276fa95188d19Tadashi G. Takaokapublic final class SuggestionStripView extends RelativeLayout implements OnClickListener, 73c412309b7a32308b1b0a175dafc13f90254353c5Tadashi G. Takaoka OnLongClickListener { 74c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka public interface Listener { 7518d688c94bb8e1e26de2d12445cb3096c6126f75Jean Chalard public void addWordToUserDictionary(String word); 769310f42a36eabe99ed7dcd3b835d6cdaa3c6fdcaJean Chalard public void pickSuggestionManually(int index, SuggestedWordInfo word); 77c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka } 78c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka 7986e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka // The maximum number of suggestions available. See {@link Suggest#mPrefMaxSuggestions}. 8029e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka public static final int MAX_SUGGESTIONS = 18; 81923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 828c3d5b6961a9b9d40c4bf21ad495f852971c24f4Tadashi G. Takaoka static final boolean DBG = LatinImeLogger.sDBG; 836f7218627eda110a8454053f8ecb7b80edfdc8cesatok 84913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka private final ViewGroup mSuggestionsStrip; 85d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka MainKeyboardView mMainKeyboardView; 8674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 8729e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka private final View mMoreSuggestionsContainer; 8829e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka private final MoreSuggestionsView mMoreSuggestionsView; 8929e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka private final MoreSuggestions.Builder mMoreSuggestionsBuilder; 9029e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka 915f282ea9e4a4590fcbab6e27d5fca7dacbb40a6aTadashi G. Takaoka private final ArrayList<TextView> mWords = CollectionUtils.newArrayList(); 925f282ea9e4a4590fcbab6e27d5fca7dacbb40a6aTadashi G. Takaoka private final ArrayList<TextView> mInfos = CollectionUtils.newArrayList(); 935f282ea9e4a4590fcbab6e27d5fca7dacbb40a6aTadashi G. Takaoka private final ArrayList<View> mDividers = CollectionUtils.newArrayList(); 9474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 953e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka Listener mListener; 966f7905ae757c30ac0f8080f025b88afc61a6f6b1Tadashi G. Takaoka private SuggestedWords mSuggestedWords = SuggestedWords.EMPTY; 976a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani 984702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka private final SuggestionStripViewParams mParams; 99ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka private static final float MIN_TEXT_XSCALE = 0.70f; 100b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka 101a28a05e971cc242b338331a3b78276fa95188d19Tadashi G. Takaoka private static final class SuggestionStripViewParams { 102d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka private static final int DEFAULT_SUGGESTIONS_COUNT_IN_STRIP = 3; 103ef2bfad5903fb55adca61dbea51984fbc7e4375fTadashi G. Takaoka private static final float DEFAULT_CENTER_SUGGESTION_PERCENTILE = 0.40f; 1049676038b6e9fb66760588d7f9c9c642cc493dd71Tadashi G. Takaoka private static final int DEFAULT_MAX_MORE_SUGGESTIONS_ROW = 2; 105293db0873fd89b5c2bd077ffa5091321b3ab8149Ken Wakasa private static final int PUNCTUATIONS_IN_STRIP = 5; 106d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka 10774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka public final int mPadding; 10874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka public final int mDividerWidth; 109913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka public final int mSuggestionsStripHeight; 110d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka public final int mSuggestionsCountInStrip; 111c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka public final int mMoreSuggestionsRowHeight; 112c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka private int mMaxMoreSuggestionsRow; 1139676038b6e9fb66760588d7f9c9c642cc493dd71Tadashi G. Takaoka public final float mMinMoreSuggestionsWidth; 1144269a7cebdfe5c76372d0f0dd187432f0594ffe5Tadashi G. Takaoka public final int mMoreSuggestionsBottomGap; 11516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka 116660776e09b9a3b321074a94721d901a035ca1b9fKen Wakasa private final ArrayList<TextView> mWords; 117660776e09b9a3b321074a94721d901a035ca1b9fKen Wakasa private final ArrayList<View> mDividers; 118660776e09b9a3b321074a94721d901a035ca1b9fKen Wakasa private final ArrayList<TextView> mInfos; 119d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka 120a44685ab326809185a0e4c44afabe8fd93441b4cTadashi G. Takaoka private final int mColorValidTypedWord; 121d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka private final int mColorTypedWord; 122d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka private final int mColorAutoCorrect; 123913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka private final int mColorSuggested; 124697bf585f8dac6ffc4d008c02b63407cfdd83104Tadashi G. Takaoka private final float mAlphaObsoleted; 125913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka private final float mCenterSuggestionWeight; 126913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka private final int mCenterSuggestionIndex; 127913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka private final Drawable mMoreSuggestionsHint; 1289bdce3a59e9bf00095bc92fae88b830b0a8455beFabrice Di Meglio private static final String MORE_SUGGESTIONS_HINT = "\u2026"; 1292eb8781dc2e42d55474fb6e5c461c56c066b8363Tadashi G. Takaoka private static final String LEFTWARDS_ARROW = "\u2190"; 130d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka 131d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka private static final CharacterStyle BOLD_SPAN = new StyleSpan(Typeface.BOLD); 132d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka private static final CharacterStyle UNDERLINE_SPAN = new UnderlineSpan(); 133d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka private static final int AUTO_CORRECT_BOLD = 0x01; 134d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka private static final int AUTO_CORRECT_UNDERLINE = 0x02; 13577a87e3cb5886b1319230906c77c0bc98b905248Tadashi G. Takaoka private static final int VALID_TYPED_WORD_BOLD = 0x04; 136d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka 137d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka private final int mSuggestionStripOption; 13874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 1395f282ea9e4a4590fcbab6e27d5fca7dacbb40a6aTadashi G. Takaoka private final ArrayList<CharSequence> mTexts = CollectionUtils.newArrayList(); 14074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 141ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka public boolean mMoreSuggestionsAvailable; 142ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka 1439f763d14451685965039990891eb0bc8e8db0735Tadashi G. Takaoka private final TextView mWordToSaveView; 1442eb8781dc2e42d55474fb6e5c461c56c066b8363Tadashi G. Takaoka private final TextView mLeftwardsArrowView; 145c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka private final TextView mHintToSaveView; 146c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka 1473e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka public SuggestionStripViewParams(final Context context, final AttributeSet attrs, 1483e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka final int defStyle, final ArrayList<TextView> words, final ArrayList<View> dividers, 1493e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka final ArrayList<TextView> infos) { 150d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka mWords = words; 151d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka mDividers = dividers; 152d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka mInfos = infos; 153d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka 154d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka final TextView word = words.get(0); 155d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka final View divider = dividers.get(0); 156d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka mPadding = word.getCompoundPaddingLeft() + word.getCompoundPaddingRight(); 157d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka divider.measure( 158d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); 159d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka mDividerWidth = divider.getMeasuredWidth(); 160d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka 161d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka final Resources res = word.getResources(); 162d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka mSuggestionsStripHeight = res.getDimensionPixelSize(R.dimen.suggestions_strip_height); 163d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka 1644702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka final TypedArray a = context.obtainStyledAttributes(attrs, 1654702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka R.styleable.SuggestionStripView, defStyle, R.style.SuggestionStripViewStyle); 1664702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka mSuggestionStripOption = a.getInt( 1674702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka R.styleable.SuggestionStripView_suggestionStripOption, 0); 16892821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka final float alphaValidTypedWord = ResourceUtils.getFraction(a, 169ef2bfad5903fb55adca61dbea51984fbc7e4375fTadashi G. Takaoka R.styleable.SuggestionStripView_alphaValidTypedWord, 1.0f); 17092821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka final float alphaTypedWord = ResourceUtils.getFraction(a, 171ef2bfad5903fb55adca61dbea51984fbc7e4375fTadashi G. Takaoka R.styleable.SuggestionStripView_alphaTypedWord, 1.0f); 17292821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka final float alphaAutoCorrect = ResourceUtils.getFraction(a, 173ef2bfad5903fb55adca61dbea51984fbc7e4375fTadashi G. Takaoka R.styleable.SuggestionStripView_alphaAutoCorrect, 1.0f); 17492821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka final float alphaSuggested = ResourceUtils.getFraction(a, 175ef2bfad5903fb55adca61dbea51984fbc7e4375fTadashi G. Takaoka R.styleable.SuggestionStripView_alphaSuggested, 1.0f); 17692821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka mAlphaObsoleted = ResourceUtils.getFraction(a, 177ef2bfad5903fb55adca61dbea51984fbc7e4375fTadashi G. Takaoka R.styleable.SuggestionStripView_alphaSuggested, 1.0f); 1784702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka mColorValidTypedWord = applyAlpha(a.getColor( 1794702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka R.styleable.SuggestionStripView_colorValidTypedWord, 0), alphaValidTypedWord); 1804702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka mColorTypedWord = applyAlpha(a.getColor( 1814702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka R.styleable.SuggestionStripView_colorTypedWord, 0), alphaTypedWord); 1824702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka mColorAutoCorrect = applyAlpha(a.getColor( 1834702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka R.styleable.SuggestionStripView_colorAutoCorrect, 0), alphaAutoCorrect); 1844702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka mColorSuggested = applyAlpha(a.getColor( 1854702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka R.styleable.SuggestionStripView_colorSuggested, 0), alphaSuggested); 186913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka mSuggestionsCountInStrip = a.getInt( 1874702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka R.styleable.SuggestionStripView_suggestionsCountInStrip, 188913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka DEFAULT_SUGGESTIONS_COUNT_IN_STRIP); 18992821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka mCenterSuggestionWeight = ResourceUtils.getFraction(a, 1904702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka R.styleable.SuggestionStripView_centerSuggestionPercentile, 191697bf585f8dac6ffc4d008c02b63407cfdd83104Tadashi G. Takaoka DEFAULT_CENTER_SUGGESTION_PERCENTILE); 1929676038b6e9fb66760588d7f9c9c642cc493dd71Tadashi G. Takaoka mMaxMoreSuggestionsRow = a.getInt( 1934702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka R.styleable.SuggestionStripView_maxMoreSuggestionsRow, 1949676038b6e9fb66760588d7f9c9c642cc493dd71Tadashi G. Takaoka DEFAULT_MAX_MORE_SUGGESTIONS_ROW); 19592821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka mMinMoreSuggestionsWidth = ResourceUtils.getFraction(a, 196ef2bfad5903fb55adca61dbea51984fbc7e4375fTadashi G. Takaoka R.styleable.SuggestionStripView_minMoreSuggestionsWidth, 1.0f); 197d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka a.recycle(); 198d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka 1990967ef40368c4bc7a0576ecc3dc222a8fe9b94c3Tadashi G. Takaoka mMoreSuggestionsHint = getMoreSuggestionsHint(res, 2000967ef40368c4bc7a0576ecc3dc222a8fe9b94c3Tadashi G. Takaoka res.getDimension(R.dimen.more_suggestions_hint_text_size), mColorAutoCorrect); 201913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka mCenterSuggestionIndex = mSuggestionsCountInStrip / 2; 2024269a7cebdfe5c76372d0f0dd187432f0594ffe5Tadashi G. Takaoka mMoreSuggestionsBottomGap = res.getDimensionPixelOffset( 2034269a7cebdfe5c76372d0f0dd187432f0594ffe5Tadashi G. Takaoka R.dimen.more_suggestions_bottom_gap); 204c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka mMoreSuggestionsRowHeight = res.getDimensionPixelSize( 205c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka R.dimen.more_suggestions_row_height); 20660a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka 207c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka final LayoutInflater inflater = LayoutInflater.from(context); 208913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka mWordToSaveView = (TextView)inflater.inflate(R.layout.suggestion_word, null); 2092eb8781dc2e42d55474fb6e5c461c56c066b8363Tadashi G. Takaoka mLeftwardsArrowView = (TextView)inflater.inflate(R.layout.hint_add_to_dictionary, null); 2102eb8781dc2e42d55474fb6e5c461c56c066b8363Tadashi G. Takaoka mHintToSaveView = (TextView)inflater.inflate(R.layout.hint_add_to_dictionary, null); 21174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka } 21274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 213c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka public int getMaxMoreSuggestionsRow() { 214c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka return mMaxMoreSuggestionsRow; 215c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka } 216c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka 217c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka private int getMoreSuggestionsHeight() { 218c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka return mMaxMoreSuggestionsRow * mMoreSuggestionsRowHeight + mMoreSuggestionsBottomGap; 219c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka } 220c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka 2213e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka public int setMoreSuggestionsHeight(final int remainingHeight) { 222c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka final int currentHeight = getMoreSuggestionsHeight(); 223c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka if (currentHeight <= remainingHeight) { 224c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka return currentHeight; 225c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka } 226c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka 227c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka mMaxMoreSuggestionsRow = (remainingHeight - mMoreSuggestionsBottomGap) 228c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka / mMoreSuggestionsRowHeight; 229c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka final int newHeight = getMoreSuggestionsHeight(); 230c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka return newHeight; 231c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka } 232c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka 2333e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka private static Drawable getMoreSuggestionsHint(final Resources res, final float textSize, 2343e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka final int color) { 2350967ef40368c4bc7a0576ecc3dc222a8fe9b94c3Tadashi G. Takaoka final Paint paint = new Paint(); 2360967ef40368c4bc7a0576ecc3dc222a8fe9b94c3Tadashi G. Takaoka paint.setAntiAlias(true); 2370967ef40368c4bc7a0576ecc3dc222a8fe9b94c3Tadashi G. Takaoka paint.setTextAlign(Align.CENTER); 2380967ef40368c4bc7a0576ecc3dc222a8fe9b94c3Tadashi G. Takaoka paint.setTextSize(textSize); 2390967ef40368c4bc7a0576ecc3dc222a8fe9b94c3Tadashi G. Takaoka paint.setColor(color); 2400967ef40368c4bc7a0576ecc3dc222a8fe9b94c3Tadashi G. Takaoka final Rect bounds = new Rect(); 241c9f562a9a4c2b634eb43d1ddaef69068c0d93f6fKen Wakasa paint.getTextBounds(MORE_SUGGESTIONS_HINT, 0, MORE_SUGGESTIONS_HINT.length(), bounds); 2420967ef40368c4bc7a0576ecc3dc222a8fe9b94c3Tadashi G. Takaoka final int width = Math.round(bounds.width() + 0.5f); 2430967ef40368c4bc7a0576ecc3dc222a8fe9b94c3Tadashi G. Takaoka final int height = Math.round(bounds.height() + 0.5f); 2440967ef40368c4bc7a0576ecc3dc222a8fe9b94c3Tadashi G. Takaoka final Bitmap buffer = Bitmap.createBitmap( 2450967ef40368c4bc7a0576ecc3dc222a8fe9b94c3Tadashi G. Takaoka width, (height * 3 / 2), Bitmap.Config.ARGB_8888); 2460967ef40368c4bc7a0576ecc3dc222a8fe9b94c3Tadashi G. Takaoka final Canvas canvas = new Canvas(buffer); 2470967ef40368c4bc7a0576ecc3dc222a8fe9b94c3Tadashi G. Takaoka canvas.drawText(MORE_SUGGESTIONS_HINT, width / 2, height, paint); 2480967ef40368c4bc7a0576ecc3dc222a8fe9b94c3Tadashi G. Takaoka return new BitmapDrawable(res, buffer); 2490967ef40368c4bc7a0576ecc3dc222a8fe9b94c3Tadashi G. Takaoka } 2500967ef40368c4bc7a0576ecc3dc222a8fe9b94c3Tadashi G. Takaoka 2513e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka private CharSequence getStyledSuggestionWord(final SuggestedWords suggestedWords, 2523e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka final int pos) { 253bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka final String word = suggestedWords.getWord(pos); 254e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka final boolean isAutoCorrect = pos == 1 && suggestedWords.willAutoCorrect(); 255e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka final boolean isTypedWordValid = pos == 0 && suggestedWords.mTypedWordValid; 256d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka if (!isAutoCorrect && !isTypedWordValid) 257d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka return word; 258d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka 259d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka final int len = word.length(); 260d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka final Spannable spannedWord = new SpannableString(word); 261d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka final int option = mSuggestionStripOption; 262d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka if ((isAutoCorrect && (option & AUTO_CORRECT_BOLD) != 0) 263d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka || (isTypedWordValid && (option & VALID_TYPED_WORD_BOLD) != 0)) { 264d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka spannedWord.setSpan(BOLD_SPAN, 0, len, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); 265d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka } 266d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka if (isAutoCorrect && (option & AUTO_CORRECT_UNDERLINE) != 0) { 267d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka spannedWord.setSpan(UNDERLINE_SPAN, 0, len, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); 268d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka } 269d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka return spannedWord; 270d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka } 271d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka 2723e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka private int getWordPosition(final int index, final SuggestedWords suggestedWords) { 27360a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka // TODO: This works for 3 suggestions. Revisit this algorithm when there are 5 or more 27460a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka // suggestions. 275e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka final int centerPos = suggestedWords.willAutoCorrect() ? 1 : 0; 276913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka if (index == mCenterSuggestionIndex) { 27760a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka return centerPos; 27860a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka } else if (index == centerPos) { 279913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka return mCenterSuggestionIndex; 28060a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka } else { 281d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka return index; 282d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka } 283d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka } 284d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka 2853e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka private int getSuggestionTextColor(final int index, final SuggestedWords suggestedWords, 2863e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka final int pos) { 287d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka // TODO: Need to revisit this logic with bigram suggestions 288913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka final boolean isSuggested = (pos != 0); 289d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka 290d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka final int color; 291e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka if (index == mCenterSuggestionIndex && suggestedWords.willAutoCorrect()) { 292d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka color = mColorAutoCorrect; 293e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka } else if (index == mCenterSuggestionIndex && suggestedWords.mTypedWordValid) { 294a44685ab326809185a0e4c44afabe8fd93441b4cTadashi G. Takaoka color = mColorValidTypedWord; 295913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka } else if (isSuggested) { 296913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka color = mColorSuggested; 297d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka } else { 298d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka color = mColorTypedWord; 299d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka } 300c0c20b386fb06b688f56dd7f807e2bcbb70b3a59Jean Chalard if (LatinImeLogger.sDBG && suggestedWords.size() > 1) { 301ebbb7e9665b2f9bce46ddc2daa82b9ef73f6c712Jean Chalard // If we auto-correct, then the autocorrection is in slot 0 and the typed word 302ebbb7e9665b2f9bce46ddc2daa82b9ef73f6c712Jean Chalard // is in slot 1. 303f72b8f5662afb42b08eb88e92731d52f99df13e3Jean Chalard if (index == mCenterSuggestionIndex 304f72b8f5662afb42b08eb88e92731d52f99df13e3Jean Chalard && AutoCorrection.shouldBlockAutoCorrectionBySafetyNet( 305bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka suggestedWords.getWord(1), suggestedWords.getWord(0))) { 3062aa1dd45c44295e2f7e8ece1b520032d86b9f908satok return 0xFFFF0000; 3072aa1dd45c44295e2f7e8ece1b520032d86b9f908satok } 3082aa1dd45c44295e2f7e8ece1b520032d86b9f908satok } 30960a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka 3104f6cf258fe208329247ade7a6701ac9709820717Jean Chalard if (suggestedWords.mIsObsoleteSuggestions && isSuggested) { 311697bf585f8dac6ffc4d008c02b63407cfdd83104Tadashi G. Takaoka return applyAlpha(color, mAlphaObsoleted); 312d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka } else { 313d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka return color; 314d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka } 315d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka } 316d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka 317d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka private static int applyAlpha(final int color, final float alpha) { 318d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka final int newAlpha = (int)(Color.alpha(color) * alpha); 319d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka return Color.argb(newAlpha, Color.red(color), Color.green(color), Color.blue(color)); 320d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka } 321d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka 3222c47080e7b4b9b2a6c2dbf1444e041c1b7943316Tadashi G. Takaoka private static void addDivider(final ViewGroup stripView, final View divider) { 3232c47080e7b4b9b2a6c2dbf1444e041c1b7943316Tadashi G. Takaoka stripView.addView(divider); 3242c47080e7b4b9b2a6c2dbf1444e041c1b7943316Tadashi G. Takaoka final LinearLayout.LayoutParams params = 3252c47080e7b4b9b2a6c2dbf1444e041c1b7943316Tadashi G. Takaoka (LinearLayout.LayoutParams)divider.getLayoutParams(); 3262c47080e7b4b9b2a6c2dbf1444e041c1b7943316Tadashi G. Takaoka params.gravity = Gravity.CENTER; 3272c47080e7b4b9b2a6c2dbf1444e041c1b7943316Tadashi G. Takaoka } 3282c47080e7b4b9b2a6c2dbf1444e041c1b7943316Tadashi G. Takaoka 3293e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka public void layout(final SuggestedWords suggestedWords, final ViewGroup stripView, 3303e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka final ViewGroup placer, final int stripWidth) { 331e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka if (suggestedWords.mIsPunctuationSuggestions) { 332e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka layoutPunctuationSuggestions(suggestedWords, stripView); 3333a566c48b0eb3625788e1cce3fb2f58d8f4b380dTadashi G. Takaoka return; 33460a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka } 33560a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka 336913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka final int countInStrip = mSuggestionsCountInStrip; 337e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka setupTexts(suggestedWords, countInStrip); 338e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka mMoreSuggestionsAvailable = (suggestedWords.size() > countInStrip); 33960a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka int x = 0; 34060a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka for (int index = 0; index < countInStrip; index++) { 341e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka final int pos = getWordPosition(index, suggestedWords); 34260a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka 34360a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka if (index != 0) { 34460a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka final View divider = mDividers.get(pos); 345913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka // Add divider if this isn't the left most suggestion in suggestions strip. 3462c47080e7b4b9b2a6c2dbf1444e041c1b7943316Tadashi G. Takaoka addDivider(stripView, divider); 347013ba3e3e785980b74db83ac5ab1e11b438485daTadashi G. Takaoka x += divider.getMeasuredWidth(); 34860a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka } 34960a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka 35016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka final CharSequence styled = mTexts.get(pos); 35160a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka final TextView word = mWords.get(pos); 352913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka if (index == mCenterSuggestionIndex && mMoreSuggestionsAvailable) { 353ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka // TODO: This "more suggestions hint" should have nicely designed icon. 354ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka word.setCompoundDrawablesWithIntrinsicBounds( 355913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka null, null, null, mMoreSuggestionsHint); 356580e1d7ac0cb90a464a3b3aed88047f85a4ab41fTadashi G. Takaoka // HACK: To align with other TextView that has no compound drawables. 357913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka word.setCompoundDrawablePadding(-mMoreSuggestionsHint.getIntrinsicHeight()); 358ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka } else { 359580e1d7ac0cb90a464a3b3aed88047f85a4ab41fTadashi G. Takaoka word.setCompoundDrawablesWithIntrinsicBounds(null, null, null, null); 360ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka } 361ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka 362913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka // Disable this suggestion if the suggestion is null or empty. 36360a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka word.setEnabled(!TextUtils.isEmpty(styled)); 364e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka word.setTextColor(getSuggestionTextColor(index, suggestedWords, pos)); 365913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka final int width = getSuggestionWidth(index, stripWidth); 36660a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka final CharSequence text = getEllipsizedText(styled, width, word.getPaint()); 36760a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka final float scaleX = word.getTextScaleX(); 36860a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka word.setText(text); // TextView.setText() resets text scale x to 1.0. 36960a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka word.setTextScaleX(scaleX); 37060a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka stripView.addView(word); 371b8dc67466339dc14653ad634c86851025373326bTadashi G. Takaoka setLayoutWeight( 372913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka word, getSuggestionWeight(index), ViewGroup.LayoutParams.MATCH_PARENT); 373013ba3e3e785980b74db83ac5ab1e11b438485daTadashi G. Takaoka x += word.getMeasuredWidth(); 37416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka 375042557b45bf2554608cd22874633011157cd1752Jean Chalard if (DBG && pos < suggestedWords.size()) { 376bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka final String debugInfo = Utils.getDebugInfo(suggestedWords, pos); 37716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka if (debugInfo != null) { 37860a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka final TextView info = mInfos.get(pos); 37916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka info.setText(debugInfo); 380013ba3e3e785980b74db83ac5ab1e11b438485daTadashi G. Takaoka placer.addView(info); 381b8dc67466339dc14653ad634c86851025373326bTadashi G. Takaoka info.measure(ViewGroup.LayoutParams.WRAP_CONTENT, 382b8dc67466339dc14653ad634c86851025373326bTadashi G. Takaoka ViewGroup.LayoutParams.WRAP_CONTENT); 38360a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka final int infoWidth = info.getMeasuredWidth(); 38416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka final int y = info.getMeasuredHeight(); 385c8461d1ae26d43a09c0f835d833f3d49fbe8d2f3Tadashi G. Takaoka ViewLayoutUtils.placeViewAt( 386013ba3e3e785980b74db83ac5ab1e11b438485daTadashi G. Takaoka info, x - infoWidth, y, infoWidth, info.getMeasuredHeight()); 38716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka } 38860a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka } 38916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka } 39016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka } 39116713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka 3923e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka private int getSuggestionWidth(final int index, final int maxWidth) { 393913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka final int paddings = mPadding * mSuggestionsCountInStrip; 394913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka final int dividers = mDividerWidth * (mSuggestionsCountInStrip - 1); 39560a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka final int availableWidth = maxWidth - paddings - dividers; 396913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka return (int)(availableWidth * getSuggestionWeight(index)); 39760a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka } 39874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 3993e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka private float getSuggestionWeight(final int index) { 400913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka if (index == mCenterSuggestionIndex) { 401913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka return mCenterSuggestionWeight; 40260a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka } else { 40360a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka // TODO: Revisit this for cases of 5 or more suggestions 404913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka return (1.0f - mCenterSuggestionWeight) / (mSuggestionsCountInStrip - 1); 40574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka } 40674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka } 40774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 4083e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka private void setupTexts(final SuggestedWords suggestedWords, final int countInStrip) { 40974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mTexts.clear(); 410e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka final int count = Math.min(suggestedWords.size(), countInStrip); 41160a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka for (int pos = 0; pos < count; pos++) { 412e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka final CharSequence styled = getStyledSuggestionWord(suggestedWords, pos); 41374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mTexts.add(styled); 41474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka } 41560a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka for (int pos = count; pos < countInStrip; pos++) { 41660a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka // Make this inactive for touches in layout(). 41760a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka mTexts.add(null); 41860a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka } 41974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka } 42074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 4213e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka private void layoutPunctuationSuggestions(final SuggestedWords suggestedWords, 4223e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka final ViewGroup stripView) { 423e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka final int countInStrip = Math.min(suggestedWords.size(), PUNCTUATIONS_IN_STRIP); 42460a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka for (int index = 0; index < countInStrip; index++) { 42560a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka if (index != 0) { 426913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka // Add divider if this isn't the left most suggestion in suggestions strip. 4272c47080e7b4b9b2a6c2dbf1444e041c1b7943316Tadashi G. Takaoka addDivider(stripView, mDividers.get(index)); 42860a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka } 42960a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka 43060a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka final TextView word = mWords.get(index); 43160a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka word.setEnabled(true); 432a44685ab326809185a0e4c44afabe8fd93441b4cTadashi G. Takaoka word.setTextColor(mColorAutoCorrect); 433bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka final String text = suggestedWords.getWord(index); 43460a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka word.setText(text); 43560a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka word.setTextScaleX(1.0f); 436ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka word.setCompoundDrawables(null, null, null, null); 43760a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka stripView.addView(word); 438913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka setLayoutWeight(word, 1.0f, mSuggestionsStripHeight); 43960a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka } 440ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka mMoreSuggestionsAvailable = false; 44174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka } 442c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka 443bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka public void layoutAddToDictionaryHint(final String word, final ViewGroup stripView, 4443e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka final int stripWidth, final CharSequence hintText, final OnClickListener listener) { 445c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka final int width = stripWidth - mDividerWidth - mPadding * 2; 446c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka 447c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka final TextView wordView = mWordToSaveView; 448c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka wordView.setTextColor(mColorTypedWord); 449913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka final int wordWidth = (int)(width * mCenterSuggestionWeight); 450c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka final CharSequence text = getEllipsizedText(word, wordWidth, wordView.getPaint()); 451c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka final float wordScaleX = wordView.getTextScaleX(); 452c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka wordView.setTag(word); 453c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka wordView.setText(text); 454c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka wordView.setTextScaleX(wordScaleX); 455c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka stripView.addView(wordView); 456913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka setLayoutWeight(wordView, mCenterSuggestionWeight, ViewGroup.LayoutParams.MATCH_PARENT); 457c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka 458c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka stripView.addView(mDividers.get(0)); 459c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka 4602eb8781dc2e42d55474fb6e5c461c56c066b8363Tadashi G. Takaoka final TextView leftArrowView = mLeftwardsArrowView; 4612eb8781dc2e42d55474fb6e5c461c56c066b8363Tadashi G. Takaoka leftArrowView.setTextColor(mColorAutoCorrect); 4622eb8781dc2e42d55474fb6e5c461c56c066b8363Tadashi G. Takaoka leftArrowView.setText(LEFTWARDS_ARROW); 4632eb8781dc2e42d55474fb6e5c461c56c066b8363Tadashi G. Takaoka stripView.addView(leftArrowView); 4642eb8781dc2e42d55474fb6e5c461c56c066b8363Tadashi G. Takaoka 465c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka final TextView hintView = mHintToSaveView; 4662eb8781dc2e42d55474fb6e5c461c56c066b8363Tadashi G. Takaoka hintView.setGravity(Gravity.LEFT | Gravity.CENTER_VERTICAL); 467c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka hintView.setTextColor(mColorAutoCorrect); 4682eb8781dc2e42d55474fb6e5c461c56c066b8363Tadashi G. Takaoka final int hintWidth = width - wordWidth - leftArrowView.getWidth(); 469644d33d60ea5a87501274488013d65f55238895eKen Wakasa final float hintScaleX = getTextScaleX(hintText, hintWidth, hintView.getPaint()); 470644d33d60ea5a87501274488013d65f55238895eKen Wakasa hintView.setText(hintText); 471c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka hintView.setTextScaleX(hintScaleX); 472c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka stripView.addView(hintView); 473b8dc67466339dc14653ad634c86851025373326bTadashi G. Takaoka setLayoutWeight( 474913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka hintView, 1.0f - mCenterSuggestionWeight, ViewGroup.LayoutParams.MATCH_PARENT); 4759f763d14451685965039990891eb0bc8e8db0735Tadashi G. Takaoka 4769f763d14451685965039990891eb0bc8e8db0735Tadashi G. Takaoka wordView.setOnClickListener(listener); 4779f763d14451685965039990891eb0bc8e8db0735Tadashi G. Takaoka leftArrowView.setOnClickListener(listener); 4789f763d14451685965039990891eb0bc8e8db0735Tadashi G. Takaoka hintView.setOnClickListener(listener); 4799f763d14451685965039990891eb0bc8e8db0735Tadashi G. Takaoka } 4809f763d14451685965039990891eb0bc8e8db0735Tadashi G. Takaoka 4819f763d14451685965039990891eb0bc8e8db0735Tadashi G. Takaoka public CharSequence getAddToDictionaryWord() { 4829f763d14451685965039990891eb0bc8e8db0735Tadashi G. Takaoka return (CharSequence)mWordToSaveView.getTag(); 4839f763d14451685965039990891eb0bc8e8db0735Tadashi G. Takaoka } 4849f763d14451685965039990891eb0bc8e8db0735Tadashi G. Takaoka 4853e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka public boolean isAddToDictionaryShowing(final View v) { 4869f763d14451685965039990891eb0bc8e8db0735Tadashi G. Takaoka return v == mWordToSaveView || v == mHintToSaveView || v == mLeftwardsArrowView; 487c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka } 4882d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka 4893e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka private static void setLayoutWeight(final View v, final float weight, final int height) { 4902d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka final ViewGroup.LayoutParams lp = v.getLayoutParams(); 4912d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka if (lp instanceof LinearLayout.LayoutParams) { 4922d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka final LinearLayout.LayoutParams llp = (LinearLayout.LayoutParams)lp; 4932d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka llp.weight = weight; 4942d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka llp.width = 0; 4952d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka llp.height = height; 4962d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka } 4972d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka } 4982d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka 4993e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka private static float getTextScaleX(final CharSequence text, final int maxWidth, 5003e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka final TextPaint paint) { 5012d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka paint.setTextScaleX(1.0f); 5022d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka final int width = getTextWidth(text, paint); 5032d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka if (width <= maxWidth) { 5042d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka return 1.0f; 5052d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka } 5062d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka return maxWidth / (float)width; 5072d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka } 5082d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka 5093e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka private static CharSequence getEllipsizedText(final CharSequence text, final int maxWidth, 5103e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka final TextPaint paint) { 5112d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka if (text == null) return null; 5122d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka paint.setTextScaleX(1.0f); 5132d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka final int width = getTextWidth(text, paint); 5142d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka if (width <= maxWidth) { 5152d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka return text; 5162d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka } 5172d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka final float scaleX = maxWidth / (float)width; 5182d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka if (scaleX >= MIN_TEXT_XSCALE) { 5192d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka paint.setTextScaleX(scaleX); 5202d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka return text; 5212d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka } 5222d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka 5232d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka // Note that TextUtils.ellipsize() use text-x-scale as 1.0 if ellipsize is needed. To 5242d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka // get squeezed and ellipsized text, passes enlarged width (maxWidth / MIN_TEXT_XSCALE). 5252d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka final CharSequence ellipsized = TextUtils.ellipsize( 5262d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka text, paint, maxWidth / MIN_TEXT_XSCALE, TextUtils.TruncateAt.MIDDLE); 5272d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka paint.setTextScaleX(MIN_TEXT_XSCALE); 5282d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka return ellipsized; 5292d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka } 5302d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka 5313e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka private static int getTextWidth(final CharSequence text, final TextPaint paint) { 5322d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka if (TextUtils.isEmpty(text)) return 0; 5332d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka final Typeface savedTypeface = paint.getTypeface(); 5342d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka paint.setTypeface(getTextTypeface(text)); 5352d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka final int len = text.length(); 5362d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka final float[] widths = new float[len]; 5372d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka final int count = paint.getTextWidths(text, 0, len, widths); 5382d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka int width = 0; 5392d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka for (int i = 0; i < count; i++) { 5402d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka width += Math.round(widths[i] + 0.5f); 5412d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka } 5422d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka paint.setTypeface(savedTypeface); 5432d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka return width; 5442d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka } 5452d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka 5463e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka private static Typeface getTextTypeface(final CharSequence text) { 5472d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka if (!(text instanceof SpannableString)) 5482d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka return Typeface.DEFAULT; 5492d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka 5502d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka final SpannableString ss = (SpannableString)text; 5512d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka final StyleSpan[] styles = ss.getSpans(0, text.length(), StyleSpan.class); 5522d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka if (styles.length == 0) 5532d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka return Typeface.DEFAULT; 5542d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka 5552d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka switch (styles[0].getStyle()) { 5562d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka case Typeface.BOLD: return Typeface.DEFAULT_BOLD; 5572d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka // TODO: BOLD_ITALIC, ITALIC case? 5582d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka default: return Typeface.DEFAULT; 5592d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka } 5602d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka } 56174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka } 56274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 563923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 5644702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka * Construct a {@link SuggestionStripView} for showing suggestions to be picked by the user. 565923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * @param context 566923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * @param attrs 567923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 5683e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka public SuggestionStripView(final Context context, final AttributeSet attrs) { 5694702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka this(context, attrs, R.attr.suggestionStripViewStyle); 57008a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka } 57108a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka 5723e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka public SuggestionStripView(final Context context, final AttributeSet attrs, 5733e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka final int defStyle) { 574c412309b7a32308b1b0a175dafc13f90254353c5Tadashi G. Takaoka super(context, attrs, defStyle); 575923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 57616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka final LayoutInflater inflater = LayoutInflater.from(context); 577913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka inflater.inflate(R.layout.suggestions_strip, this); 57886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka 579913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka mSuggestionsStrip = (ViewGroup)findViewById(R.id.suggestions_strip); 58060a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka for (int pos = 0; pos < MAX_SUGGESTIONS; pos++) { 581913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka final TextView word = (TextView)inflater.inflate(R.layout.suggestion_word, null); 58260a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka word.setTag(pos); 5832442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka word.setOnClickListener(this); 584ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka word.setOnLongClickListener(this); 5852442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka mWords.add(word); 586913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka final View divider = inflater.inflate(R.layout.suggestion_divider, null); 58760a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka divider.setTag(pos); 588a1aab83a24e74cb0fad4b1c1e59b18d23ecbdad3Tadashi G. Takaoka divider.setOnClickListener(this); 589a1aab83a24e74cb0fad4b1c1e59b18d23ecbdad3Tadashi G. Takaoka mDividers.add(divider); 590913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka mInfos.add((TextView)inflater.inflate(R.layout.suggestion_info, null)); 591c9716b28ce438e06b5cacc07fc002944bcbe24a0Tadashi G. Takaoka } 592179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaoka 5934702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka mParams = new SuggestionStripViewParams( 5944702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka context, attrs, defStyle, mWords, mDividers, mInfos); 59529e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka 59629e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka mMoreSuggestionsContainer = inflater.inflate(R.layout.more_suggestions, null); 59729e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka mMoreSuggestionsView = (MoreSuggestionsView)mMoreSuggestionsContainer 59829e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka .findViewById(R.id.more_suggestions_view); 59908ae0d5ca03ed455827e82222df249d1cafb5d71Tadashi G. Takaoka mMoreSuggestionsBuilder = new MoreSuggestions.Builder(context, mMoreSuggestionsView); 600bfc1d732ac92fa1bd5b19ad9e7c71ce9a1f9dc00Tadashi G. Takaoka 60150e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka final Resources res = context.getResources(); 60250e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka mMoreSuggestionsModalTolerance = res.getDimensionPixelOffset( 60350e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka R.dimen.more_suggestions_modal_tolerance); 6043fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka mMoreSuggestionsSlidingDetector = new GestureDetector( 6053fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka context, mMoreSuggestionsSlidingListener); 606923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 607c9716b28ce438e06b5cacc07fc002944bcbe24a0Tadashi G. Takaoka 608923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 609c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka * A connection back to the input method. 610923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * @param listener 611923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 6123e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka public void setListener(final Listener listener, final View inputView) { 613c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka mListener = listener; 614d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka mMainKeyboardView = (MainKeyboardView)inputView.findViewById(R.id.keyboard_view); 615923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 616923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 6173e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka public void setSuggestions(final SuggestedWords suggestedWords) { 618e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka clear(); 619e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka mSuggestedWords = suggestedWords; 620e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka mParams.layout(mSuggestedWords, mSuggestionsStrip, this, getWidth()); 6219c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) { 6224702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka ResearchLogger.suggestionStripView_setSuggestions(mSuggestedWords); 623a9ca7867b5a7c0be115966211a05f5d460c8638cKurt Partridge } 62416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka } 62574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 6263e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka public int setMoreSuggestionsHeight(final int remainingHeight) { 627c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka return mParams.setMoreSuggestionsHeight(remainingHeight); 628c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka } 629b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka 630b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani public boolean isShowingAddToDictionaryHint() { 631913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka return mSuggestionsStrip.getChildCount() > 0 6329f763d14451685965039990891eb0bc8e8db0735Tadashi G. Takaoka && mParams.isAddToDictionaryShowing(mSuggestionsStrip.getChildAt(0)); 633b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani } 634b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani 635bc464e2952e102219f0b977fc1e9140ad5bd03e4Tadashi G. Takaoka public void showAddToDictionaryHint(final String word, final CharSequence hintText) { 636c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka clear(); 6379f763d14451685965039990891eb0bc8e8db0735Tadashi G. Takaoka mParams.layoutAddToDictionaryHint(word, mSuggestionsStrip, getWidth(), hintText, this); 63866a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani } 63966a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani 6406558253160e2039c87f424bd814f402ecd31de3bKen Wakasa public boolean dismissAddToDictionaryHint() { 641c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka if (isShowingAddToDictionaryHint()) { 642c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka clear(); 643c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka return true; 644c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka } 645c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka return false; 6466558253160e2039c87f424bd814f402ecd31de3bKen Wakasa } 6476558253160e2039c87f424bd814f402ecd31de3bKen Wakasa 648923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public void clear() { 649913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka mSuggestionsStrip.removeAllViews(); 650c412309b7a32308b1b0a175dafc13f90254353c5Tadashi G. Takaoka removeAllViews(); 651c412309b7a32308b1b0a175dafc13f90254353c5Tadashi G. Takaoka addView(mSuggestionsStrip); 6521b087064c07975c5e2b9c17d4ca80c56e01c35c0Tadashi G. Takaoka dismissMoreSuggestions(); 653923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 654923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 6556f7905ae757c30ac0f8080f025b88afc61a6f6b1Tadashi G. Takaoka private final MoreSuggestionsListener mMoreSuggestionsListener = new MoreSuggestionsListener() { 65629e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka @Override 6576f7905ae757c30ac0f8080f025b88afc61a6f6b1Tadashi G. Takaoka public void onSuggestionSelected(final int index, final SuggestedWordInfo wordInfo) { 6589310f42a36eabe99ed7dcd3b835d6cdaa3c6fdcaJean Chalard mListener.pickSuggestionManually(index, wordInfo); 6591b087064c07975c5e2b9c17d4ca80c56e01c35c0Tadashi G. Takaoka dismissMoreSuggestions(); 66029e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka } 66129e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka 66229e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka @Override 66329e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka public void onCancelInput() { 6641b087064c07975c5e2b9c17d4ca80c56e01c35c0Tadashi G. Takaoka dismissMoreSuggestions(); 66529e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka } 66629e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka }; 66729e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka 66829e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka private final MoreKeysPanel.Controller mMoreSuggestionsController = 66929e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka new MoreKeysPanel.Controller() { 67029e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka @Override 671fa2d543785c52f639ad3157c57420f58a199c550Tom Ouyang public boolean onDismissMoreKeysPanel() { 672d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka return mMainKeyboardView.onDismissMoreKeysPanel(); 673fa2d543785c52f639ad3157c57420f58a199c550Tom Ouyang } 674fa2d543785c52f639ad3157c57420f58a199c550Tom Ouyang 675fa2d543785c52f639ad3157c57420f58a199c550Tom Ouyang @Override 676a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka public void onShowMoreKeysPanel(final MoreKeysPanel panel) { 677d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka mMainKeyboardView.onShowMoreKeysPanel(panel); 67829e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka } 679ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang 680ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang @Override 681ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang public void onCancelMoreKeysPanel() { 682ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang dismissMoreSuggestions(); 683ac69ab400d1ea4f90b4ca24486d62212decf1069Tom Ouyang } 68429e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka }; 68529e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka 6863e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka boolean dismissMoreSuggestions() { 687fa2d543785c52f639ad3157c57420f58a199c550Tom Ouyang return mMoreSuggestionsView.dismissMoreKeysPanel(); 6881b087064c07975c5e2b9c17d4ca80c56e01c35c0Tadashi G. Takaoka } 6891b087064c07975c5e2b9c17d4ca80c56e01c35c0Tadashi G. Takaoka 690e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka @Override 6913e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka public boolean onLongClick(final View view) { 6925faf41951929301af80026bc3191812ef874fd5aTadashi G. Takaoka KeyboardSwitcher.getInstance().hapticAndAudioFeedback(Constants.NOT_A_CODE); 6933fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka return showMoreSuggestions(); 6943fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka } 6953fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka 6963e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka boolean showMoreSuggestions() { 6977339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka final Keyboard parentKeyboard = KeyboardSwitcher.getInstance().getKeyboard(); 6987339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka if (parentKeyboard == null) { 6997339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka return false; 700ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka } 7017339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka final SuggestionStripViewParams params = mParams; 7027339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka if (!params.mMoreSuggestionsAvailable) { 7037339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka return false; 7047339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka } 7057339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka final int stripWidth = getWidth(); 7067339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka final View container = mMoreSuggestionsContainer; 7077339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka final int maxWidth = stripWidth - container.getPaddingLeft() - container.getPaddingRight(); 7087339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka final MoreSuggestions.Builder builder = mMoreSuggestionsBuilder; 7097339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka builder.layout(mSuggestedWords, params.mSuggestionsCountInStrip, maxWidth, 7107339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka (int)(maxWidth * params.mMinMoreSuggestionsWidth), 7117339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka params.getMaxMoreSuggestionsRow(), parentKeyboard); 7127339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka mMoreSuggestionsView.setKeyboard(builder.build()); 7137339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka container.measure(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); 7147339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka 7157339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka final MoreKeysPanel moreKeysPanel = mMoreSuggestionsView; 7167339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka final int pointX = stripWidth / 2; 7177339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka final int pointY = -params.mMoreSuggestionsBottomGap; 7187339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka moreKeysPanel.showMoreKeysPanel(this, mMoreSuggestionsController, pointX, pointY, 719fa2d543785c52f639ad3157c57420f58a199c550Tom Ouyang mMoreSuggestionsListener); 7207339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka mMoreSuggestionsMode = MORE_SUGGESTIONS_CHECKING_MODAL_OR_SLIDING; 7217339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka mOriginX = mLastX; 7227339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka mOriginY = mLastY; 7237339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka for (int i = 0; i < params.mSuggestionsCountInStrip; i++) { 7247339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka mWords.get(i).setPressed(false); 7257339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka } 7267339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka return true; 727ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka } 728ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka 72950e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka // Working variables for onLongClick and dispatchTouchEvent. 730d7b00f34904c61f955e439160e2dbaa3a4b6983cTadashi G. Takaoka private int mMoreSuggestionsMode = MORE_SUGGESTIONS_IN_MODAL_MODE; 731d7b00f34904c61f955e439160e2dbaa3a4b6983cTadashi G. Takaoka private static final int MORE_SUGGESTIONS_IN_MODAL_MODE = 0; 732d7b00f34904c61f955e439160e2dbaa3a4b6983cTadashi G. Takaoka private static final int MORE_SUGGESTIONS_CHECKING_MODAL_OR_SLIDING = 1; 733d7b00f34904c61f955e439160e2dbaa3a4b6983cTadashi G. Takaoka private static final int MORE_SUGGESTIONS_IN_SLIDING_MODE = 2; 73450e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka private int mLastX; 73550e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka private int mLastY; 73650e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka private int mOriginX; 73750e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka private int mOriginY; 73850e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka private final int mMoreSuggestionsModalTolerance; 7393fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka private final GestureDetector mMoreSuggestionsSlidingDetector; 7403fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka private final GestureDetector.OnGestureListener mMoreSuggestionsSlidingListener = 7413fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka new GestureDetector.SimpleOnGestureListener() { 7423fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka @Override 7433fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka public boolean onScroll(MotionEvent down, MotionEvent me, float deltaX, float deltaY) { 7443fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka final float dy = me.getY() - down.getY(); 7453fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka if (deltaY > 0 && dy < 0) { 7463fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka return showMoreSuggestions(); 7473fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka } 7483fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka return false; 7493fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka } 7503fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka }; 75150e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka 752ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka @Override 7533e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka public boolean dispatchTouchEvent(final MotionEvent me) { 75451c38a441a09a4920703e765cb26179e7a80f029Tadashi G. Takaoka if (!mMoreSuggestionsView.isShowingInParent()) { 75550e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka mLastX = (int)me.getX(); 75650e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka mLastY = (int)me.getY(); 7573fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka if (mMoreSuggestionsSlidingDetector.onTouchEvent(me)) { 7583fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka return true; 7593fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka } 76029e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka return super.dispatchTouchEvent(me); 76129e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka } 7628ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka 7638ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka final MoreKeysPanel moreKeysPanel = mMoreSuggestionsView; 76429e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka final int action = me.getAction(); 76529e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka final long eventTime = me.getEventTime(); 76629e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka final int index = me.getActionIndex(); 76729e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka final int id = me.getPointerId(index); 7688ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka final int x = (int)me.getX(index); 7698ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka final int y = (int)me.getY(index); 7708ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka final int translatedX = moreKeysPanel.translateX(x); 7718ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka final int translatedY = moreKeysPanel.translateY(y); 7728ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka 773d7b00f34904c61f955e439160e2dbaa3a4b6983cTadashi G. Takaoka if (mMoreSuggestionsMode == MORE_SUGGESTIONS_CHECKING_MODAL_OR_SLIDING) { 77487104bace9cb9ed1a700f05a37743a21c2722fffTadashi G. Takaoka if (Math.abs(x - mOriginX) >= mMoreSuggestionsModalTolerance 77587104bace9cb9ed1a700f05a37743a21c2722fffTadashi G. Takaoka || mOriginY - y >= mMoreSuggestionsModalTolerance) { 77687104bace9cb9ed1a700f05a37743a21c2722fffTadashi G. Takaoka // Decided to be in the sliding input mode only when the touch point has been moved 77787104bace9cb9ed1a700f05a37743a21c2722fffTadashi G. Takaoka // upward. 778d7b00f34904c61f955e439160e2dbaa3a4b6983cTadashi G. Takaoka mMoreSuggestionsMode = MORE_SUGGESTIONS_IN_SLIDING_MODE; 77950e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka } else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_POINTER_UP) { 78050e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka // Decided to be in the modal input mode 781d7b00f34904c61f955e439160e2dbaa3a4b6983cTadashi G. Takaoka mMoreSuggestionsMode = MORE_SUGGESTIONS_IN_MODAL_MODE; 78251c38a441a09a4920703e765cb26179e7a80f029Tadashi G. Takaoka mMoreSuggestionsView.adjustVerticalCorrectionForModalMode(); 78350e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka } 78450e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka return true; 78550e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka } 78650e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka 787d7b00f34904c61f955e439160e2dbaa3a4b6983cTadashi G. Takaoka // MORE_SUGGESTIONS_IN_SLIDING_MODE 78835580bad6f3da3b204653825bbb6871563e70728Tom Ouyang mMoreSuggestionsView.processMotionEvent(action, translatedX, translatedY, id, eventTime); 78929e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka return true; 79029e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka } 79129e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka 79229e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka @Override 7933e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka public void onClick(final View view) { 7949f763d14451685965039990891eb0bc8e8db0735Tadashi G. Takaoka if (mParams.isAddToDictionaryShowing(view)) { 7953d8e7a62fc6182c12ca28c29ceeee52ed4b9eea7Jean Chalard mListener.addWordToUserDictionary(mParams.getAddToDictionaryWord().toString()); 796717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka clear(); 797717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka return; 798717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka } 799717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka 80086e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka final Object tag = view.getTag(); 80186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka if (!(tag instanceof Integer)) 80286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka return; 80386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka final int index = (Integer) tag; 804e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka if (index >= mSuggestedWords.size()) 80537deb112c727dfed5e94d054cf5f00f5d60c8120Tadashi G. Takaoka return; 80686e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka 8079310f42a36eabe99ed7dcd3b835d6cdaa3c6fdcaJean Chalard final SuggestedWordInfo wordInfo = mSuggestedWords.getInfo(index); 8089310f42a36eabe99ed7dcd3b835d6cdaa3c6fdcaJean Chalard mListener.pickSuggestionManually(index, wordInfo); 809923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 81082411d47ba7e8133ed2390c6920945e139a738cesatok 8116ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani @Override 81273cd4c1428ac370e1c15c5f61b1ce499f0d4f4c7Tadashi G. Takaoka protected void onDetachedFromWindow() { 8136ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani super.onDetachedFromWindow(); 81432f4ceb2434b6f204cf8152b406d0f9a642feb73Tadashi G. Takaoka dismissMoreSuggestions(); 8156ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani } 816923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project} 817