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