SuggestionStripView.java revision 3e5a3c18bebbfb56012383411b24ee81ffde09cb
1923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project/* 2913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka * Copyright (C) 2011 The Android Open Source Project 3e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka * 4923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * use this file except in compliance with the License. You may obtain a copy of 6923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * the License at 7e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka * 8923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 9e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka * 10923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 11923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * License for the specific language governing permissions and limitations under 14923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * the License. 15923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 16923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 178c3d5b6961a9b9d40c4bf21ad495f852971c24f4Tadashi G. Takaokapackage com.android.inputmethod.latin.suggestions; 18923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 19923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.Context; 2066a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasaniimport android.content.res.Resources; 2108a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaokaimport android.content.res.TypedArray; 220967ef40368c4bc7a0576ecc3dc222a8fe9b94c3Tadashi G. Takaokaimport android.graphics.Bitmap; 230967ef40368c4bc7a0576ecc3dc222a8fe9b94c3Tadashi G. Takaokaimport android.graphics.Canvas; 246f7218627eda110a8454053f8ecb7b80edfdc8cesatokimport android.graphics.Color; 250967ef40368c4bc7a0576ecc3dc222a8fe9b94c3Tadashi G. Takaokaimport android.graphics.Paint; 260967ef40368c4bc7a0576ecc3dc222a8fe9b94c3Tadashi G. Takaokaimport android.graphics.Paint.Align; 270967ef40368c4bc7a0576ecc3dc222a8fe9b94c3Tadashi G. Takaokaimport android.graphics.Rect; 28923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.graphics.Typeface; 290967ef40368c4bc7a0576ecc3dc222a8fe9b94c3Tadashi G. Takaokaimport android.graphics.drawable.BitmapDrawable; 30bfc1d732ac92fa1bd5b19ad9e7c71ce9a1f9dc00Tadashi G. Takaokaimport android.graphics.drawable.ColorDrawable; 31e583371b13ebd9aa336d0883e8c174ae4918c758Tadashi G. Takaokaimport android.graphics.drawable.Drawable; 32e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaokaimport android.os.Message; 33522d5c16d20657e7d26009fe9c067404e16a6c2aTadashi G. Takaokaimport android.text.Spannable; 34522d5c16d20657e7d26009fe9c067404e16a6c2aTadashi G. Takaokaimport android.text.SpannableString; 35e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaokaimport android.text.Spanned; 36b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaokaimport android.text.TextPaint; 37e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaokaimport android.text.TextUtils; 38522d5c16d20657e7d26009fe9c067404e16a6c2aTadashi G. Takaokaimport android.text.style.CharacterStyle; 3974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaokaimport android.text.style.StyleSpan; 40522d5c16d20657e7d26009fe9c067404e16a6c2aTadashi G. Takaokaimport android.text.style.UnderlineSpan; 41923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.util.AttributeSet; 423fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaokaimport android.view.GestureDetector; 43923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.Gravity; 44923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.LayoutInflater; 4529e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaokaimport android.view.MotionEvent; 46923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.View; 47e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaokaimport android.view.View.OnClickListener; 48ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaokaimport android.view.View.OnLongClickListener; 49e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaokaimport android.view.ViewGroup; 50e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaokaimport android.widget.LinearLayout; 51923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.widget.PopupWindow; 52c412309b7a32308b1b0a175dafc13f90254353c5Tadashi G. Takaokaimport android.widget.RelativeLayout; 53923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.widget.TextView; 54923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 557339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaokaimport com.android.inputmethod.keyboard.Keyboard; 5629e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaokaimport com.android.inputmethod.keyboard.KeyboardActionListener; 577339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaokaimport com.android.inputmethod.keyboard.KeyboardSwitcher; 581b087064c07975c5e2b9c17d4ca80c56e01c35c0Tadashi G. Takaokaimport com.android.inputmethod.keyboard.KeyboardView; 5929e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaokaimport com.android.inputmethod.keyboard.MoreKeysPanel; 6029e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaokaimport com.android.inputmethod.keyboard.PointerTracker; 61c8461d1ae26d43a09c0f835d833f3d49fbe8d2f3Tadashi G. Takaokaimport com.android.inputmethod.keyboard.ViewLayoutUtils; 62f72b8f5662afb42b08eb88e92731d52f99df13e3Jean Chalardimport com.android.inputmethod.latin.AutoCorrection; 635f282ea9e4a4590fcbab6e27d5fca7dacbb40a6aTadashi G. Takaokaimport com.android.inputmethod.latin.CollectionUtils; 648c3d5b6961a9b9d40c4bf21ad495f852971c24f4Tadashi G. Takaokaimport com.android.inputmethod.latin.LatinImeLogger; 658c3d5b6961a9b9d40c4bf21ad495f852971c24f4Tadashi G. Takaokaimport com.android.inputmethod.latin.R; 6692821614fd80112527e133f069e31ee48250314fTadashi G. Takaokaimport com.android.inputmethod.latin.ResourceUtils; 678c3d5b6961a9b9d40c4bf21ad495f852971c24f4Tadashi G. Takaokaimport com.android.inputmethod.latin.StaticInnerHandlerWrapper; 688c3d5b6961a9b9d40c4bf21ad495f852971c24f4Tadashi G. Takaokaimport com.android.inputmethod.latin.SuggestedWords; 69042557b45bf2554608cd22874633011157cd1752Jean Chalardimport com.android.inputmethod.latin.Utils; 70a9ca7867b5a7c0be115966211a05f5d460c8638cKurt Partridgeimport com.android.inputmethod.latin.define.ProductionFlag; 716b966160ac8570271547bf63217efa5e228d4accKurt Partridgeimport com.android.inputmethod.research.ResearchLogger; 72ddb61ea461b920d87be4ad78c8a36eec1013b965Tadashi G. Takaoka 73179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaokaimport java.util.ArrayList; 74179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaoka 75a28a05e971cc242b338331a3b78276fa95188d19Tadashi G. Takaokapublic final class SuggestionStripView extends RelativeLayout implements OnClickListener, 76c412309b7a32308b1b0a175dafc13f90254353c5Tadashi G. Takaoka OnLongClickListener { 77c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka public interface Listener { 783d8e7a62fc6182c12ca28c29ceeee52ed4b9eea7Jean Chalard public boolean addWordToUserDictionary(String word); 796785b9072762e15bb49657ce7b7d228dab76e44aTadashi G. Takaoka public void pickSuggestionManually(int index, CharSequence word); 80c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka } 81c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka 8286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka // The maximum number of suggestions available. See {@link Suggest#mPrefMaxSuggestions}. 8329e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka public static final int MAX_SUGGESTIONS = 18; 84923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 858c3d5b6961a9b9d40c4bf21ad495f852971c24f4Tadashi G. Takaoka static final boolean DBG = LatinImeLogger.sDBG; 866f7218627eda110a8454053f8ecb7b80edfdc8cesatok 87913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka private final ViewGroup mSuggestionsStrip; 883e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka KeyboardView mKeyboardView; 8974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 9029e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka private final View mMoreSuggestionsContainer; 9129e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka private final MoreSuggestionsView mMoreSuggestionsView; 9229e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka private final MoreSuggestions.Builder mMoreSuggestionsBuilder; 9329e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka private final PopupWindow mMoreSuggestionsWindow; 9429e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka 955f282ea9e4a4590fcbab6e27d5fca7dacbb40a6aTadashi G. Takaoka private final ArrayList<TextView> mWords = CollectionUtils.newArrayList(); 965f282ea9e4a4590fcbab6e27d5fca7dacbb40a6aTadashi G. Takaoka private final ArrayList<TextView> mInfos = CollectionUtils.newArrayList(); 975f282ea9e4a4590fcbab6e27d5fca7dacbb40a6aTadashi G. Takaoka private final ArrayList<View> mDividers = CollectionUtils.newArrayList(); 9874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 9982411d47ba7e8133ed2390c6920945e139a738cesatok private final PopupWindow mPreviewPopup; 10082411d47ba7e8133ed2390c6920945e139a738cesatok private final TextView mPreviewText; 10166a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani 1023e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka Listener mListener; 1033e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka SuggestedWords mSuggestedWords = SuggestedWords.EMPTY; 1046a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani 1054702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka private final SuggestionStripViewParams mParams; 106ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka private static final float MIN_TEXT_XSCALE = 0.70f; 107b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka 1084f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa private final UiHandler mHandler = new UiHandler(this); 10955b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 110a28a05e971cc242b338331a3b78276fa95188d19Tadashi G. Takaoka private static final class UiHandler extends StaticInnerHandlerWrapper<SuggestionStripView> { 11155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka private static final int MSG_HIDE_PREVIEW = 0; 11255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 1133e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka public UiHandler(final SuggestionStripView outerInstance) { 1144f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa super(outerInstance); 1154f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa } 1164f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa 117e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka @Override 1183e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka public void dispatchMessage(final Message msg) { 1194702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka final SuggestionStripView suggestionStripView = getOuterInstance(); 120e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka switch (msg.what) { 121e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka case MSG_HIDE_PREVIEW: 1224702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka suggestionStripView.hidePreview(); 123e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka break; 124e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka } 125e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka } 12655b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 12755b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka public void cancelHidePreview() { 12855b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka removeMessages(MSG_HIDE_PREVIEW); 12955b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka } 13055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 13155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka public void cancelAllMessages() { 13255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka cancelHidePreview(); 13355b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka } 134e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka } 135179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaoka 136a28a05e971cc242b338331a3b78276fa95188d19Tadashi G. Takaoka private static final class SuggestionStripViewParams { 137d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka private static final int DEFAULT_SUGGESTIONS_COUNT_IN_STRIP = 3; 138ef2bfad5903fb55adca61dbea51984fbc7e4375fTadashi G. Takaoka private static final float DEFAULT_CENTER_SUGGESTION_PERCENTILE = 0.40f; 1399676038b6e9fb66760588d7f9c9c642cc493dd71Tadashi G. Takaoka private static final int DEFAULT_MAX_MORE_SUGGESTIONS_ROW = 2; 140293db0873fd89b5c2bd077ffa5091321b3ab8149Ken Wakasa private static final int PUNCTUATIONS_IN_STRIP = 5; 141d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka 14274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka public final int mPadding; 14374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka public final int mDividerWidth; 144913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka public final int mSuggestionsStripHeight; 145d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka public final int mSuggestionsCountInStrip; 146c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka public final int mMoreSuggestionsRowHeight; 147c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka private int mMaxMoreSuggestionsRow; 1489676038b6e9fb66760588d7f9c9c642cc493dd71Tadashi G. Takaoka public final float mMinMoreSuggestionsWidth; 1494269a7cebdfe5c76372d0f0dd187432f0594ffe5Tadashi G. Takaoka public final int mMoreSuggestionsBottomGap; 15016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka 151660776e09b9a3b321074a94721d901a035ca1b9fKen Wakasa private final ArrayList<TextView> mWords; 152660776e09b9a3b321074a94721d901a035ca1b9fKen Wakasa private final ArrayList<View> mDividers; 153660776e09b9a3b321074a94721d901a035ca1b9fKen Wakasa private final ArrayList<TextView> mInfos; 154d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka 155a44685ab326809185a0e4c44afabe8fd93441b4cTadashi G. Takaoka private final int mColorValidTypedWord; 156d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka private final int mColorTypedWord; 157d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka private final int mColorAutoCorrect; 158913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka private final int mColorSuggested; 159697bf585f8dac6ffc4d008c02b63407cfdd83104Tadashi G. Takaoka private final float mAlphaObsoleted; 160913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka private final float mCenterSuggestionWeight; 161913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka private final int mCenterSuggestionIndex; 162913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka private final Drawable mMoreSuggestionsHint; 1639bdce3a59e9bf00095bc92fae88b830b0a8455beFabrice Di Meglio private static final String MORE_SUGGESTIONS_HINT = "\u2026"; 1642eb8781dc2e42d55474fb6e5c461c56c066b8363Tadashi G. Takaoka private static final String LEFTWARDS_ARROW = "\u2190"; 165d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka 166d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka private static final CharacterStyle BOLD_SPAN = new StyleSpan(Typeface.BOLD); 167d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka private static final CharacterStyle UNDERLINE_SPAN = new UnderlineSpan(); 168d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka private static final int AUTO_CORRECT_BOLD = 0x01; 169d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka private static final int AUTO_CORRECT_UNDERLINE = 0x02; 17077a87e3cb5886b1319230906c77c0bc98b905248Tadashi G. Takaoka private static final int VALID_TYPED_WORD_BOLD = 0x04; 171d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka 172d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka private final int mSuggestionStripOption; 17374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 1745f282ea9e4a4590fcbab6e27d5fca7dacbb40a6aTadashi G. Takaoka private final ArrayList<CharSequence> mTexts = CollectionUtils.newArrayList(); 17574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 176ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka public boolean mMoreSuggestionsAvailable; 177ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka 1789f763d14451685965039990891eb0bc8e8db0735Tadashi G. Takaoka private final TextView mWordToSaveView; 1792eb8781dc2e42d55474fb6e5c461c56c066b8363Tadashi G. Takaoka private final TextView mLeftwardsArrowView; 180c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka private final TextView mHintToSaveView; 181c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka 1823e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka public SuggestionStripViewParams(final Context context, final AttributeSet attrs, 1833e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka final int defStyle, final ArrayList<TextView> words, final ArrayList<View> dividers, 1843e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka final ArrayList<TextView> infos) { 185d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka mWords = words; 186d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka mDividers = dividers; 187d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka mInfos = infos; 188d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka 189d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka final TextView word = words.get(0); 190d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka final View divider = dividers.get(0); 191d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka mPadding = word.getCompoundPaddingLeft() + word.getCompoundPaddingRight(); 192d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka divider.measure( 193d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); 194d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka mDividerWidth = divider.getMeasuredWidth(); 195d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka 196d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka final Resources res = word.getResources(); 197d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka mSuggestionsStripHeight = res.getDimensionPixelSize(R.dimen.suggestions_strip_height); 198d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka 1994702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka final TypedArray a = context.obtainStyledAttributes(attrs, 2004702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka R.styleable.SuggestionStripView, defStyle, R.style.SuggestionStripViewStyle); 2014702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka mSuggestionStripOption = a.getInt( 2024702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka R.styleable.SuggestionStripView_suggestionStripOption, 0); 20392821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka final float alphaValidTypedWord = ResourceUtils.getFraction(a, 204ef2bfad5903fb55adca61dbea51984fbc7e4375fTadashi G. Takaoka R.styleable.SuggestionStripView_alphaValidTypedWord, 1.0f); 20592821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka final float alphaTypedWord = ResourceUtils.getFraction(a, 206ef2bfad5903fb55adca61dbea51984fbc7e4375fTadashi G. Takaoka R.styleable.SuggestionStripView_alphaTypedWord, 1.0f); 20792821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka final float alphaAutoCorrect = ResourceUtils.getFraction(a, 208ef2bfad5903fb55adca61dbea51984fbc7e4375fTadashi G. Takaoka R.styleable.SuggestionStripView_alphaAutoCorrect, 1.0f); 20992821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka final float alphaSuggested = ResourceUtils.getFraction(a, 210ef2bfad5903fb55adca61dbea51984fbc7e4375fTadashi G. Takaoka R.styleable.SuggestionStripView_alphaSuggested, 1.0f); 21192821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka mAlphaObsoleted = ResourceUtils.getFraction(a, 212ef2bfad5903fb55adca61dbea51984fbc7e4375fTadashi G. Takaoka R.styleable.SuggestionStripView_alphaSuggested, 1.0f); 2134702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka mColorValidTypedWord = applyAlpha(a.getColor( 2144702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka R.styleable.SuggestionStripView_colorValidTypedWord, 0), alphaValidTypedWord); 2154702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka mColorTypedWord = applyAlpha(a.getColor( 2164702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka R.styleable.SuggestionStripView_colorTypedWord, 0), alphaTypedWord); 2174702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka mColorAutoCorrect = applyAlpha(a.getColor( 2184702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka R.styleable.SuggestionStripView_colorAutoCorrect, 0), alphaAutoCorrect); 2194702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka mColorSuggested = applyAlpha(a.getColor( 2204702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka R.styleable.SuggestionStripView_colorSuggested, 0), alphaSuggested); 221913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka mSuggestionsCountInStrip = a.getInt( 2224702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka R.styleable.SuggestionStripView_suggestionsCountInStrip, 223913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka DEFAULT_SUGGESTIONS_COUNT_IN_STRIP); 22492821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka mCenterSuggestionWeight = ResourceUtils.getFraction(a, 2254702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka R.styleable.SuggestionStripView_centerSuggestionPercentile, 226697bf585f8dac6ffc4d008c02b63407cfdd83104Tadashi G. Takaoka DEFAULT_CENTER_SUGGESTION_PERCENTILE); 2279676038b6e9fb66760588d7f9c9c642cc493dd71Tadashi G. Takaoka mMaxMoreSuggestionsRow = a.getInt( 2284702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka R.styleable.SuggestionStripView_maxMoreSuggestionsRow, 2299676038b6e9fb66760588d7f9c9c642cc493dd71Tadashi G. Takaoka DEFAULT_MAX_MORE_SUGGESTIONS_ROW); 23092821614fd80112527e133f069e31ee48250314fTadashi G. Takaoka mMinMoreSuggestionsWidth = ResourceUtils.getFraction(a, 231ef2bfad5903fb55adca61dbea51984fbc7e4375fTadashi G. Takaoka R.styleable.SuggestionStripView_minMoreSuggestionsWidth, 1.0f); 232d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka a.recycle(); 233d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka 2340967ef40368c4bc7a0576ecc3dc222a8fe9b94c3Tadashi G. Takaoka mMoreSuggestionsHint = getMoreSuggestionsHint(res, 2350967ef40368c4bc7a0576ecc3dc222a8fe9b94c3Tadashi G. Takaoka res.getDimension(R.dimen.more_suggestions_hint_text_size), mColorAutoCorrect); 236913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka mCenterSuggestionIndex = mSuggestionsCountInStrip / 2; 2374269a7cebdfe5c76372d0f0dd187432f0594ffe5Tadashi G. Takaoka mMoreSuggestionsBottomGap = res.getDimensionPixelOffset( 2384269a7cebdfe5c76372d0f0dd187432f0594ffe5Tadashi G. Takaoka R.dimen.more_suggestions_bottom_gap); 239c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka mMoreSuggestionsRowHeight = res.getDimensionPixelSize( 240c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka R.dimen.more_suggestions_row_height); 24160a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka 242c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka final LayoutInflater inflater = LayoutInflater.from(context); 243913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka mWordToSaveView = (TextView)inflater.inflate(R.layout.suggestion_word, null); 2442eb8781dc2e42d55474fb6e5c461c56c066b8363Tadashi G. Takaoka mLeftwardsArrowView = (TextView)inflater.inflate(R.layout.hint_add_to_dictionary, null); 2452eb8781dc2e42d55474fb6e5c461c56c066b8363Tadashi G. Takaoka mHintToSaveView = (TextView)inflater.inflate(R.layout.hint_add_to_dictionary, null); 24674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka } 24774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 248c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka public int getMaxMoreSuggestionsRow() { 249c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka return mMaxMoreSuggestionsRow; 250c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka } 251c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka 252c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka private int getMoreSuggestionsHeight() { 253c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka return mMaxMoreSuggestionsRow * mMoreSuggestionsRowHeight + mMoreSuggestionsBottomGap; 254c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka } 255c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka 2563e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka public int setMoreSuggestionsHeight(final int remainingHeight) { 257c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka final int currentHeight = getMoreSuggestionsHeight(); 258c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka if (currentHeight <= remainingHeight) { 259c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka return currentHeight; 260c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka } 261c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka 262c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka mMaxMoreSuggestionsRow = (remainingHeight - mMoreSuggestionsBottomGap) 263c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka / mMoreSuggestionsRowHeight; 264c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka final int newHeight = getMoreSuggestionsHeight(); 265c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka return newHeight; 266c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka } 267c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka 2683e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka private static Drawable getMoreSuggestionsHint(final Resources res, final float textSize, 2693e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka final int color) { 2700967ef40368c4bc7a0576ecc3dc222a8fe9b94c3Tadashi G. Takaoka final Paint paint = new Paint(); 2710967ef40368c4bc7a0576ecc3dc222a8fe9b94c3Tadashi G. Takaoka paint.setAntiAlias(true); 2720967ef40368c4bc7a0576ecc3dc222a8fe9b94c3Tadashi G. Takaoka paint.setTextAlign(Align.CENTER); 2730967ef40368c4bc7a0576ecc3dc222a8fe9b94c3Tadashi G. Takaoka paint.setTextSize(textSize); 2740967ef40368c4bc7a0576ecc3dc222a8fe9b94c3Tadashi G. Takaoka paint.setColor(color); 2750967ef40368c4bc7a0576ecc3dc222a8fe9b94c3Tadashi G. Takaoka final Rect bounds = new Rect(); 276c9f562a9a4c2b634eb43d1ddaef69068c0d93f6fKen Wakasa paint.getTextBounds(MORE_SUGGESTIONS_HINT, 0, MORE_SUGGESTIONS_HINT.length(), bounds); 2770967ef40368c4bc7a0576ecc3dc222a8fe9b94c3Tadashi G. Takaoka final int width = Math.round(bounds.width() + 0.5f); 2780967ef40368c4bc7a0576ecc3dc222a8fe9b94c3Tadashi G. Takaoka final int height = Math.round(bounds.height() + 0.5f); 2790967ef40368c4bc7a0576ecc3dc222a8fe9b94c3Tadashi G. Takaoka final Bitmap buffer = Bitmap.createBitmap( 2800967ef40368c4bc7a0576ecc3dc222a8fe9b94c3Tadashi G. Takaoka width, (height * 3 / 2), Bitmap.Config.ARGB_8888); 2810967ef40368c4bc7a0576ecc3dc222a8fe9b94c3Tadashi G. Takaoka final Canvas canvas = new Canvas(buffer); 2820967ef40368c4bc7a0576ecc3dc222a8fe9b94c3Tadashi G. Takaoka canvas.drawText(MORE_SUGGESTIONS_HINT, width / 2, height, paint); 2830967ef40368c4bc7a0576ecc3dc222a8fe9b94c3Tadashi G. Takaoka return new BitmapDrawable(res, buffer); 2840967ef40368c4bc7a0576ecc3dc222a8fe9b94c3Tadashi G. Takaoka } 2850967ef40368c4bc7a0576ecc3dc222a8fe9b94c3Tadashi G. Takaoka 2863e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka private CharSequence getStyledSuggestionWord(final SuggestedWords suggestedWords, 2873e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka final int pos) { 288e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka final CharSequence word = suggestedWords.getWord(pos); 289e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka final boolean isAutoCorrect = pos == 1 && suggestedWords.willAutoCorrect(); 290e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka final boolean isTypedWordValid = pos == 0 && suggestedWords.mTypedWordValid; 291d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka if (!isAutoCorrect && !isTypedWordValid) 292d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka return word; 293d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka 294d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka final int len = word.length(); 295d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka final Spannable spannedWord = new SpannableString(word); 296d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka final int option = mSuggestionStripOption; 297d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka if ((isAutoCorrect && (option & AUTO_CORRECT_BOLD) != 0) 298d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka || (isTypedWordValid && (option & VALID_TYPED_WORD_BOLD) != 0)) { 299d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka spannedWord.setSpan(BOLD_SPAN, 0, len, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); 300d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka } 301d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka if (isAutoCorrect && (option & AUTO_CORRECT_UNDERLINE) != 0) { 302d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka spannedWord.setSpan(UNDERLINE_SPAN, 0, len, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); 303d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka } 304d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka return spannedWord; 305d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka } 306d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka 3073e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka private int getWordPosition(final int index, final SuggestedWords suggestedWords) { 30860a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka // TODO: This works for 3 suggestions. Revisit this algorithm when there are 5 or more 30960a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka // suggestions. 310e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka final int centerPos = suggestedWords.willAutoCorrect() ? 1 : 0; 311913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka if (index == mCenterSuggestionIndex) { 31260a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka return centerPos; 31360a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka } else if (index == centerPos) { 314913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka return mCenterSuggestionIndex; 31560a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka } else { 316d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka return index; 317d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka } 318d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka } 319d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka 3203e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka private int getSuggestionTextColor(final int index, final SuggestedWords suggestedWords, 3213e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka final int pos) { 322d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka // TODO: Need to revisit this logic with bigram suggestions 323913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka final boolean isSuggested = (pos != 0); 324d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka 325d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka final int color; 326e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka if (index == mCenterSuggestionIndex && suggestedWords.willAutoCorrect()) { 327d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka color = mColorAutoCorrect; 328e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka } else if (index == mCenterSuggestionIndex && suggestedWords.mTypedWordValid) { 329a44685ab326809185a0e4c44afabe8fd93441b4cTadashi G. Takaoka color = mColorValidTypedWord; 330913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka } else if (isSuggested) { 331913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka color = mColorSuggested; 332d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka } else { 333d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka color = mColorTypedWord; 334d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka } 335c0c20b386fb06b688f56dd7f807e2bcbb70b3a59Jean Chalard if (LatinImeLogger.sDBG && suggestedWords.size() > 1) { 336ebbb7e9665b2f9bce46ddc2daa82b9ef73f6c712Jean Chalard // If we auto-correct, then the autocorrection is in slot 0 and the typed word 337ebbb7e9665b2f9bce46ddc2daa82b9ef73f6c712Jean Chalard // is in slot 1. 338f72b8f5662afb42b08eb88e92731d52f99df13e3Jean Chalard if (index == mCenterSuggestionIndex 339f72b8f5662afb42b08eb88e92731d52f99df13e3Jean Chalard && AutoCorrection.shouldBlockAutoCorrectionBySafetyNet( 340f72b8f5662afb42b08eb88e92731d52f99df13e3Jean Chalard suggestedWords.getWord(1).toString(), suggestedWords.getWord(0))) { 3412aa1dd45c44295e2f7e8ece1b520032d86b9f908satok return 0xFFFF0000; 3422aa1dd45c44295e2f7e8ece1b520032d86b9f908satok } 3432aa1dd45c44295e2f7e8ece1b520032d86b9f908satok } 34460a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka 3454f6cf258fe208329247ade7a6701ac9709820717Jean Chalard if (suggestedWords.mIsObsoleteSuggestions && isSuggested) { 346697bf585f8dac6ffc4d008c02b63407cfdd83104Tadashi G. Takaoka return applyAlpha(color, mAlphaObsoleted); 347d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka } else { 348d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka return color; 349d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka } 350d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka } 351d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka 352d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka private static int applyAlpha(final int color, final float alpha) { 353d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka final int newAlpha = (int)(Color.alpha(color) * alpha); 354d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka return Color.argb(newAlpha, Color.red(color), Color.green(color), Color.blue(color)); 355d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka } 356d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka 3572c47080e7b4b9b2a6c2dbf1444e041c1b7943316Tadashi G. Takaoka private static void addDivider(final ViewGroup stripView, final View divider) { 3582c47080e7b4b9b2a6c2dbf1444e041c1b7943316Tadashi G. Takaoka stripView.addView(divider); 3592c47080e7b4b9b2a6c2dbf1444e041c1b7943316Tadashi G. Takaoka final LinearLayout.LayoutParams params = 3602c47080e7b4b9b2a6c2dbf1444e041c1b7943316Tadashi G. Takaoka (LinearLayout.LayoutParams)divider.getLayoutParams(); 3612c47080e7b4b9b2a6c2dbf1444e041c1b7943316Tadashi G. Takaoka params.gravity = Gravity.CENTER; 3622c47080e7b4b9b2a6c2dbf1444e041c1b7943316Tadashi G. Takaoka } 3632c47080e7b4b9b2a6c2dbf1444e041c1b7943316Tadashi G. Takaoka 3643e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka public void layout(final SuggestedWords suggestedWords, final ViewGroup stripView, 3653e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka final ViewGroup placer, final int stripWidth) { 366e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka if (suggestedWords.mIsPunctuationSuggestions) { 367e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka layoutPunctuationSuggestions(suggestedWords, stripView); 3683a566c48b0eb3625788e1cce3fb2f58d8f4b380dTadashi G. Takaoka return; 36960a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka } 37060a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka 371913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka final int countInStrip = mSuggestionsCountInStrip; 372e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka setupTexts(suggestedWords, countInStrip); 373e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka mMoreSuggestionsAvailable = (suggestedWords.size() > countInStrip); 37460a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka int x = 0; 37560a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka for (int index = 0; index < countInStrip; index++) { 376e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka final int pos = getWordPosition(index, suggestedWords); 37760a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka 37860a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka if (index != 0) { 37960a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka final View divider = mDividers.get(pos); 380913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka // Add divider if this isn't the left most suggestion in suggestions strip. 3812c47080e7b4b9b2a6c2dbf1444e041c1b7943316Tadashi G. Takaoka addDivider(stripView, divider); 382013ba3e3e785980b74db83ac5ab1e11b438485daTadashi G. Takaoka x += divider.getMeasuredWidth(); 38360a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka } 38460a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka 38516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka final CharSequence styled = mTexts.get(pos); 38660a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka final TextView word = mWords.get(pos); 387913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka if (index == mCenterSuggestionIndex && mMoreSuggestionsAvailable) { 388ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka // TODO: This "more suggestions hint" should have nicely designed icon. 389ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka word.setCompoundDrawablesWithIntrinsicBounds( 390913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka null, null, null, mMoreSuggestionsHint); 391580e1d7ac0cb90a464a3b3aed88047f85a4ab41fTadashi G. Takaoka // HACK: To align with other TextView that has no compound drawables. 392913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka word.setCompoundDrawablePadding(-mMoreSuggestionsHint.getIntrinsicHeight()); 393ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka } else { 394580e1d7ac0cb90a464a3b3aed88047f85a4ab41fTadashi G. Takaoka word.setCompoundDrawablesWithIntrinsicBounds(null, null, null, null); 395ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka } 396ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka 397913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka // Disable this suggestion if the suggestion is null or empty. 39860a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka word.setEnabled(!TextUtils.isEmpty(styled)); 399e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka word.setTextColor(getSuggestionTextColor(index, suggestedWords, pos)); 400913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka final int width = getSuggestionWidth(index, stripWidth); 40160a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka final CharSequence text = getEllipsizedText(styled, width, word.getPaint()); 40260a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka final float scaleX = word.getTextScaleX(); 40360a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka word.setText(text); // TextView.setText() resets text scale x to 1.0. 40460a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka word.setTextScaleX(scaleX); 40560a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka stripView.addView(word); 406b8dc67466339dc14653ad634c86851025373326bTadashi G. Takaoka setLayoutWeight( 407913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka word, getSuggestionWeight(index), ViewGroup.LayoutParams.MATCH_PARENT); 408013ba3e3e785980b74db83ac5ab1e11b438485daTadashi G. Takaoka x += word.getMeasuredWidth(); 40916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka 410042557b45bf2554608cd22874633011157cd1752Jean Chalard if (DBG && pos < suggestedWords.size()) { 411042557b45bf2554608cd22874633011157cd1752Jean Chalard final CharSequence debugInfo = Utils.getDebugInfo(suggestedWords, pos); 41216713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka if (debugInfo != null) { 41360a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka final TextView info = mInfos.get(pos); 41416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka info.setText(debugInfo); 415013ba3e3e785980b74db83ac5ab1e11b438485daTadashi G. Takaoka placer.addView(info); 416b8dc67466339dc14653ad634c86851025373326bTadashi G. Takaoka info.measure(ViewGroup.LayoutParams.WRAP_CONTENT, 417b8dc67466339dc14653ad634c86851025373326bTadashi G. Takaoka ViewGroup.LayoutParams.WRAP_CONTENT); 41860a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka final int infoWidth = info.getMeasuredWidth(); 41916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka final int y = info.getMeasuredHeight(); 420c8461d1ae26d43a09c0f835d833f3d49fbe8d2f3Tadashi G. Takaoka ViewLayoutUtils.placeViewAt( 421013ba3e3e785980b74db83ac5ab1e11b438485daTadashi G. Takaoka info, x - infoWidth, y, infoWidth, info.getMeasuredHeight()); 42216713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka } 42360a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka } 42416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka } 42516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka } 42616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka 4273e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka private int getSuggestionWidth(final int index, final int maxWidth) { 428913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka final int paddings = mPadding * mSuggestionsCountInStrip; 429913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka final int dividers = mDividerWidth * (mSuggestionsCountInStrip - 1); 43060a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka final int availableWidth = maxWidth - paddings - dividers; 431913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka return (int)(availableWidth * getSuggestionWeight(index)); 43260a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka } 43374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 4343e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka private float getSuggestionWeight(final int index) { 435913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka if (index == mCenterSuggestionIndex) { 436913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka return mCenterSuggestionWeight; 43760a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka } else { 43860a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka // TODO: Revisit this for cases of 5 or more suggestions 439913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka return (1.0f - mCenterSuggestionWeight) / (mSuggestionsCountInStrip - 1); 44074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka } 44174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka } 44274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 4433e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka private void setupTexts(final SuggestedWords suggestedWords, final int countInStrip) { 44474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mTexts.clear(); 445e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka final int count = Math.min(suggestedWords.size(), countInStrip); 44660a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka for (int pos = 0; pos < count; pos++) { 447e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka final CharSequence styled = getStyledSuggestionWord(suggestedWords, pos); 44874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mTexts.add(styled); 44974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka } 45060a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka for (int pos = count; pos < countInStrip; pos++) { 45160a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka // Make this inactive for touches in layout(). 45260a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka mTexts.add(null); 45360a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka } 45474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka } 45574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 4563e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka private void layoutPunctuationSuggestions(final SuggestedWords suggestedWords, 4573e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka final ViewGroup stripView) { 458e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka final int countInStrip = Math.min(suggestedWords.size(), PUNCTUATIONS_IN_STRIP); 45960a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka for (int index = 0; index < countInStrip; index++) { 46060a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka if (index != 0) { 461913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka // Add divider if this isn't the left most suggestion in suggestions strip. 4622c47080e7b4b9b2a6c2dbf1444e041c1b7943316Tadashi G. Takaoka addDivider(stripView, mDividers.get(index)); 46360a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka } 46460a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka 46560a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka final TextView word = mWords.get(index); 46660a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka word.setEnabled(true); 467a44685ab326809185a0e4c44afabe8fd93441b4cTadashi G. Takaoka word.setTextColor(mColorAutoCorrect); 468e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka final CharSequence text = suggestedWords.getWord(index); 46960a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka word.setText(text); 47060a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka word.setTextScaleX(1.0f); 471ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka word.setCompoundDrawables(null, null, null, null); 47260a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka stripView.addView(word); 473913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka setLayoutWeight(word, 1.0f, mSuggestionsStripHeight); 47460a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka } 475ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka mMoreSuggestionsAvailable = false; 47674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka } 477c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka 4783e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka public void layoutAddToDictionaryHint(final CharSequence word, final ViewGroup stripView, 4793e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka final int stripWidth, final CharSequence hintText, final OnClickListener listener) { 480c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka final int width = stripWidth - mDividerWidth - mPadding * 2; 481c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka 482c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka final TextView wordView = mWordToSaveView; 483c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka wordView.setTextColor(mColorTypedWord); 484913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka final int wordWidth = (int)(width * mCenterSuggestionWeight); 485c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka final CharSequence text = getEllipsizedText(word, wordWidth, wordView.getPaint()); 486c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka final float wordScaleX = wordView.getTextScaleX(); 487c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka wordView.setTag(word); 488c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka wordView.setText(text); 489c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka wordView.setTextScaleX(wordScaleX); 490c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka stripView.addView(wordView); 491913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka setLayoutWeight(wordView, mCenterSuggestionWeight, ViewGroup.LayoutParams.MATCH_PARENT); 492c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka 493c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka stripView.addView(mDividers.get(0)); 494c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka 4952eb8781dc2e42d55474fb6e5c461c56c066b8363Tadashi G. Takaoka final TextView leftArrowView = mLeftwardsArrowView; 4962eb8781dc2e42d55474fb6e5c461c56c066b8363Tadashi G. Takaoka leftArrowView.setTextColor(mColorAutoCorrect); 4972eb8781dc2e42d55474fb6e5c461c56c066b8363Tadashi G. Takaoka leftArrowView.setText(LEFTWARDS_ARROW); 4982eb8781dc2e42d55474fb6e5c461c56c066b8363Tadashi G. Takaoka stripView.addView(leftArrowView); 4992eb8781dc2e42d55474fb6e5c461c56c066b8363Tadashi G. Takaoka 500c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka final TextView hintView = mHintToSaveView; 5012eb8781dc2e42d55474fb6e5c461c56c066b8363Tadashi G. Takaoka hintView.setGravity(Gravity.LEFT | Gravity.CENTER_VERTICAL); 502c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka hintView.setTextColor(mColorAutoCorrect); 5032eb8781dc2e42d55474fb6e5c461c56c066b8363Tadashi G. Takaoka final int hintWidth = width - wordWidth - leftArrowView.getWidth(); 504644d33d60ea5a87501274488013d65f55238895eKen Wakasa final float hintScaleX = getTextScaleX(hintText, hintWidth, hintView.getPaint()); 505644d33d60ea5a87501274488013d65f55238895eKen Wakasa hintView.setText(hintText); 506c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka hintView.setTextScaleX(hintScaleX); 507c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka stripView.addView(hintView); 508b8dc67466339dc14653ad634c86851025373326bTadashi G. Takaoka setLayoutWeight( 509913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka hintView, 1.0f - mCenterSuggestionWeight, ViewGroup.LayoutParams.MATCH_PARENT); 5109f763d14451685965039990891eb0bc8e8db0735Tadashi G. Takaoka 5119f763d14451685965039990891eb0bc8e8db0735Tadashi G. Takaoka wordView.setOnClickListener(listener); 5129f763d14451685965039990891eb0bc8e8db0735Tadashi G. Takaoka leftArrowView.setOnClickListener(listener); 5139f763d14451685965039990891eb0bc8e8db0735Tadashi G. Takaoka hintView.setOnClickListener(listener); 5149f763d14451685965039990891eb0bc8e8db0735Tadashi G. Takaoka } 5159f763d14451685965039990891eb0bc8e8db0735Tadashi G. Takaoka 5169f763d14451685965039990891eb0bc8e8db0735Tadashi G. Takaoka public CharSequence getAddToDictionaryWord() { 5179f763d14451685965039990891eb0bc8e8db0735Tadashi G. Takaoka return (CharSequence)mWordToSaveView.getTag(); 5189f763d14451685965039990891eb0bc8e8db0735Tadashi G. Takaoka } 5199f763d14451685965039990891eb0bc8e8db0735Tadashi G. Takaoka 5203e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka public boolean isAddToDictionaryShowing(final View v) { 5219f763d14451685965039990891eb0bc8e8db0735Tadashi G. Takaoka return v == mWordToSaveView || v == mHintToSaveView || v == mLeftwardsArrowView; 522c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka } 5232d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka 5243e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka private static void setLayoutWeight(final View v, final float weight, final int height) { 5252d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka final ViewGroup.LayoutParams lp = v.getLayoutParams(); 5262d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka if (lp instanceof LinearLayout.LayoutParams) { 5272d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka final LinearLayout.LayoutParams llp = (LinearLayout.LayoutParams)lp; 5282d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka llp.weight = weight; 5292d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka llp.width = 0; 5302d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka llp.height = height; 5312d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka } 5322d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka } 5332d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka 5343e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka private static float getTextScaleX(final CharSequence text, final int maxWidth, 5353e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka final TextPaint paint) { 5362d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka paint.setTextScaleX(1.0f); 5372d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka final int width = getTextWidth(text, paint); 5382d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka if (width <= maxWidth) { 5392d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka return 1.0f; 5402d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka } 5412d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka return maxWidth / (float)width; 5422d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka } 5432d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka 5443e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka private static CharSequence getEllipsizedText(final CharSequence text, final int maxWidth, 5453e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka final TextPaint paint) { 5462d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka if (text == null) return null; 5472d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka paint.setTextScaleX(1.0f); 5482d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka final int width = getTextWidth(text, paint); 5492d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka if (width <= maxWidth) { 5502d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka return text; 5512d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka } 5522d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka final float scaleX = maxWidth / (float)width; 5532d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka if (scaleX >= MIN_TEXT_XSCALE) { 5542d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka paint.setTextScaleX(scaleX); 5552d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka return text; 5562d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka } 5572d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka 5582d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka // Note that TextUtils.ellipsize() use text-x-scale as 1.0 if ellipsize is needed. To 5592d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka // get squeezed and ellipsized text, passes enlarged width (maxWidth / MIN_TEXT_XSCALE). 5602d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka final CharSequence ellipsized = TextUtils.ellipsize( 5612d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka text, paint, maxWidth / MIN_TEXT_XSCALE, TextUtils.TruncateAt.MIDDLE); 5622d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka paint.setTextScaleX(MIN_TEXT_XSCALE); 5632d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka return ellipsized; 5642d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka } 5652d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka 5663e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka private static int getTextWidth(final CharSequence text, final TextPaint paint) { 5672d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka if (TextUtils.isEmpty(text)) return 0; 5682d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka final Typeface savedTypeface = paint.getTypeface(); 5692d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka paint.setTypeface(getTextTypeface(text)); 5702d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka final int len = text.length(); 5712d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka final float[] widths = new float[len]; 5722d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka final int count = paint.getTextWidths(text, 0, len, widths); 5732d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka int width = 0; 5742d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka for (int i = 0; i < count; i++) { 5752d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka width += Math.round(widths[i] + 0.5f); 5762d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka } 5772d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka paint.setTypeface(savedTypeface); 5782d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka return width; 5792d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka } 5802d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka 5813e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka private static Typeface getTextTypeface(final CharSequence text) { 5822d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka if (!(text instanceof SpannableString)) 5832d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka return Typeface.DEFAULT; 5842d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka 5852d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka final SpannableString ss = (SpannableString)text; 5862d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka final StyleSpan[] styles = ss.getSpans(0, text.length(), StyleSpan.class); 5872d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka if (styles.length == 0) 5882d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka return Typeface.DEFAULT; 5892d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka 5902d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka switch (styles[0].getStyle()) { 5912d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka case Typeface.BOLD: return Typeface.DEFAULT_BOLD; 5922d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka // TODO: BOLD_ITALIC, ITALIC case? 5932d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka default: return Typeface.DEFAULT; 5942d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka } 5952d74806262431ce25b159e1ec5c6ac4a26007c3eTadashi G. Takaoka } 59674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka } 59774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 598923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 5994702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka * Construct a {@link SuggestionStripView} for showing suggestions to be picked by the user. 600923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * @param context 601923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * @param attrs 602923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 6033e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka public SuggestionStripView(final Context context, final AttributeSet attrs) { 6044702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka this(context, attrs, R.attr.suggestionStripViewStyle); 60508a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka } 60608a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka 6073e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka public SuggestionStripView(final Context context, final AttributeSet attrs, 6083e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka final int defStyle) { 609c412309b7a32308b1b0a175dafc13f90254353c5Tadashi G. Takaoka super(context, attrs, defStyle); 610923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 61116713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka final LayoutInflater inflater = LayoutInflater.from(context); 612913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka inflater.inflate(R.layout.suggestions_strip, this); 61386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka 61486e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka mPreviewPopup = new PopupWindow(context); 615913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka mPreviewText = (TextView) inflater.inflate(R.layout.suggestion_preview, null); 616b8dc67466339dc14653ad634c86851025373326bTadashi G. Takaoka mPreviewPopup.setWindowLayoutMode( 617b8dc67466339dc14653ad634c86851025373326bTadashi G. Takaoka ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); 618923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project mPreviewPopup.setContentView(mPreviewText); 619923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project mPreviewPopup.setBackgroundDrawable(null); 620923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 621913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka mSuggestionsStrip = (ViewGroup)findViewById(R.id.suggestions_strip); 62260a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka for (int pos = 0; pos < MAX_SUGGESTIONS; pos++) { 623913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka final TextView word = (TextView)inflater.inflate(R.layout.suggestion_word, null); 62460a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka word.setTag(pos); 6252442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka word.setOnClickListener(this); 626ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka word.setOnLongClickListener(this); 6272442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka mWords.add(word); 628913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka final View divider = inflater.inflate(R.layout.suggestion_divider, null); 62960a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka divider.setTag(pos); 630a1aab83a24e74cb0fad4b1c1e59b18d23ecbdad3Tadashi G. Takaoka divider.setOnClickListener(this); 631a1aab83a24e74cb0fad4b1c1e59b18d23ecbdad3Tadashi G. Takaoka mDividers.add(divider); 632913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka mInfos.add((TextView)inflater.inflate(R.layout.suggestion_info, null)); 633c9716b28ce438e06b5cacc07fc002944bcbe24a0Tadashi G. Takaoka } 634179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaoka 6354702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka mParams = new SuggestionStripViewParams( 6364702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka context, attrs, defStyle, mWords, mDividers, mInfos); 63729e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka 63829e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka mMoreSuggestionsContainer = inflater.inflate(R.layout.more_suggestions, null); 63929e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka mMoreSuggestionsView = (MoreSuggestionsView)mMoreSuggestionsContainer 64029e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka .findViewById(R.id.more_suggestions_view); 64129e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka mMoreSuggestionsBuilder = new MoreSuggestions.Builder(mMoreSuggestionsView); 642bfc1d732ac92fa1bd5b19ad9e7c71ce9a1f9dc00Tadashi G. Takaoka 643bfc1d732ac92fa1bd5b19ad9e7c71ce9a1f9dc00Tadashi G. Takaoka final PopupWindow moreWindow = new PopupWindow(context); 644bfc1d732ac92fa1bd5b19ad9e7c71ce9a1f9dc00Tadashi G. Takaoka moreWindow.setWindowLayoutMode( 64529e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); 646bfc1d732ac92fa1bd5b19ad9e7c71ce9a1f9dc00Tadashi G. Takaoka moreWindow.setBackgroundDrawable(new ColorDrawable(android.R.color.transparent)); 647bfc1d732ac92fa1bd5b19ad9e7c71ce9a1f9dc00Tadashi G. Takaoka moreWindow.setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED); 648bfc1d732ac92fa1bd5b19ad9e7c71ce9a1f9dc00Tadashi G. Takaoka moreWindow.setFocusable(true); 649bfc1d732ac92fa1bd5b19ad9e7c71ce9a1f9dc00Tadashi G. Takaoka moreWindow.setOutsideTouchable(true); 650bfc1d732ac92fa1bd5b19ad9e7c71ce9a1f9dc00Tadashi G. Takaoka moreWindow.setOnDismissListener(new PopupWindow.OnDismissListener() { 651bfc1d732ac92fa1bd5b19ad9e7c71ce9a1f9dc00Tadashi G. Takaoka @Override 652bfc1d732ac92fa1bd5b19ad9e7c71ce9a1f9dc00Tadashi G. Takaoka public void onDismiss() { 653bfc1d732ac92fa1bd5b19ad9e7c71ce9a1f9dc00Tadashi G. Takaoka mKeyboardView.dimEntireKeyboard(false); 654bfc1d732ac92fa1bd5b19ad9e7c71ce9a1f9dc00Tadashi G. Takaoka } 655bfc1d732ac92fa1bd5b19ad9e7c71ce9a1f9dc00Tadashi G. Takaoka }); 656bfc1d732ac92fa1bd5b19ad9e7c71ce9a1f9dc00Tadashi G. Takaoka mMoreSuggestionsWindow = moreWindow; 657bfc1d732ac92fa1bd5b19ad9e7c71ce9a1f9dc00Tadashi G. Takaoka 65850e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka final Resources res = context.getResources(); 65950e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka mMoreSuggestionsModalTolerance = res.getDimensionPixelOffset( 66050e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka R.dimen.more_suggestions_modal_tolerance); 6613fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka mMoreSuggestionsSlidingDetector = new GestureDetector( 6623fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka context, mMoreSuggestionsSlidingListener); 663923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 664c9716b28ce438e06b5cacc07fc002944bcbe24a0Tadashi G. Takaoka 665923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 666c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka * A connection back to the input method. 667923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * @param listener 668923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 6693e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka public void setListener(final Listener listener, final View inputView) { 670c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka mListener = listener; 6711b087064c07975c5e2b9c17d4ca80c56e01c35c0Tadashi G. Takaoka mKeyboardView = (KeyboardView)inputView.findViewById(R.id.keyboard_view); 672923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 673923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 6743e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka public void setSuggestions(final SuggestedWords suggestedWords) { 675d5b765b3bbceb80b2e145ac7f4d66acbadd1ee4fJean Chalard if (suggestedWords == null) 676a15e45ef45931ba46678b39c159518d8aa2d4d65Tadashi G. Takaoka return; 67755b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 678e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka clear(); 679e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka mSuggestedWords = suggestedWords; 680e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka mParams.layout(mSuggestedWords, mSuggestionsStrip, this, getWidth()); 681a9ca7867b5a7c0be115966211a05f5d460c8638cKurt Partridge if (ProductionFlag.IS_EXPERIMENTAL) { 6824702671ea4feb0c79a879e2e3013afdd6ed800b1Tadashi G. Takaoka ResearchLogger.suggestionStripView_setSuggestions(mSuggestedWords); 683a9ca7867b5a7c0be115966211a05f5d460c8638cKurt Partridge } 68416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka } 68574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 6863e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka public int setMoreSuggestionsHeight(final int remainingHeight) { 687c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka return mParams.setMoreSuggestionsHeight(remainingHeight); 688c8b0e5797e20d3fa25d319a9709aabc9149f8ff9Tadashi G. Takaoka } 689b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka 690b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani public boolean isShowingAddToDictionaryHint() { 691913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka return mSuggestionsStrip.getChildCount() > 0 6929f763d14451685965039990891eb0bc8e8db0735Tadashi G. Takaoka && mParams.isAddToDictionaryShowing(mSuggestionsStrip.getChildAt(0)); 693b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani } 694b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani 6953e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka public void showAddToDictionaryHint(final CharSequence word, final CharSequence hintText) { 696c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka clear(); 6979f763d14451685965039990891eb0bc8e8db0735Tadashi G. Takaoka mParams.layoutAddToDictionaryHint(word, mSuggestionsStrip, getWidth(), hintText, this); 69866a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani } 69966a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani 7006558253160e2039c87f424bd814f402ecd31de3bKen Wakasa public boolean dismissAddToDictionaryHint() { 701c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka if (isShowingAddToDictionaryHint()) { 702c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka clear(); 703c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka return true; 704c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka } 705c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka return false; 7066558253160e2039c87f424bd814f402ecd31de3bKen Wakasa } 7076558253160e2039c87f424bd814f402ecd31de3bKen Wakasa 7087e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka public SuggestedWords getSuggestions() { 709e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka return mSuggestedWords; 710979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 711979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 712923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public void clear() { 713913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka mSuggestionsStrip.removeAllViews(); 714c412309b7a32308b1b0a175dafc13f90254353c5Tadashi G. Takaoka removeAllViews(); 715c412309b7a32308b1b0a175dafc13f90254353c5Tadashi G. Takaoka addView(mSuggestionsStrip); 7161b087064c07975c5e2b9c17d4ca80c56e01c35c0Tadashi G. Takaoka dismissMoreSuggestions(); 717923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 718923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 7193e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka void hidePreview() { 720179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaoka mPreviewPopup.dismiss(); 7216ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani } 722e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka 72329e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka private final KeyboardActionListener mMoreSuggestionsListener = 72429e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka new KeyboardActionListener.Adapter() { 72529e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka @Override 7263e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka public boolean onCustomRequest(final int requestCode) { 72729e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka final int index = requestCode; 728e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka final CharSequence word = mSuggestedWords.getWord(index); 7296785b9072762e15bb49657ce7b7d228dab76e44aTadashi G. Takaoka mListener.pickSuggestionManually(index, word); 7301b087064c07975c5e2b9c17d4ca80c56e01c35c0Tadashi G. Takaoka dismissMoreSuggestions(); 73129e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka return true; 73229e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka } 73329e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka 73429e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka @Override 73529e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka public void onCancelInput() { 7361b087064c07975c5e2b9c17d4ca80c56e01c35c0Tadashi G. Takaoka dismissMoreSuggestions(); 73729e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka } 73829e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka }; 73929e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka 74029e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka private final MoreKeysPanel.Controller mMoreSuggestionsController = 74129e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka new MoreKeysPanel.Controller() { 74229e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka @Override 74329e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka public boolean dismissMoreKeysPanel() { 7441b087064c07975c5e2b9c17d4ca80c56e01c35c0Tadashi G. Takaoka return dismissMoreSuggestions(); 74529e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka } 74629e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka }; 74729e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka 7483e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka boolean dismissMoreSuggestions() { 7491b087064c07975c5e2b9c17d4ca80c56e01c35c0Tadashi G. Takaoka if (mMoreSuggestionsWindow.isShowing()) { 7501b087064c07975c5e2b9c17d4ca80c56e01c35c0Tadashi G. Takaoka mMoreSuggestionsWindow.dismiss(); 7511b087064c07975c5e2b9c17d4ca80c56e01c35c0Tadashi G. Takaoka return true; 7521b087064c07975c5e2b9c17d4ca80c56e01c35c0Tadashi G. Takaoka } 7531b087064c07975c5e2b9c17d4ca80c56e01c35c0Tadashi G. Takaoka return false; 7541b087064c07975c5e2b9c17d4ca80c56e01c35c0Tadashi G. Takaoka } 7551b087064c07975c5e2b9c17d4ca80c56e01c35c0Tadashi G. Takaoka 756e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka @Override 7573e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka public boolean onLongClick(final View view) { 7583fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka return showMoreSuggestions(); 7593fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka } 7603fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka 7613e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka boolean showMoreSuggestions() { 7627339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka final Keyboard parentKeyboard = KeyboardSwitcher.getInstance().getKeyboard(); 7637339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka if (parentKeyboard == null) { 7647339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka return false; 765ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka } 7667339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka final SuggestionStripViewParams params = mParams; 7677339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka if (!params.mMoreSuggestionsAvailable) { 7687339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka return false; 7697339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka } 7707339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka final int stripWidth = getWidth(); 7717339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka final View container = mMoreSuggestionsContainer; 7727339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka final int maxWidth = stripWidth - container.getPaddingLeft() - container.getPaddingRight(); 7737339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka final MoreSuggestions.Builder builder = mMoreSuggestionsBuilder; 7747339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka builder.layout(mSuggestedWords, params.mSuggestionsCountInStrip, maxWidth, 7757339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka (int)(maxWidth * params.mMinMoreSuggestionsWidth), 7767339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka params.getMaxMoreSuggestionsRow(), parentKeyboard); 7777339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka mMoreSuggestionsView.setKeyboard(builder.build()); 7787339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka container.measure(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); 7797339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka 7807339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka final MoreKeysPanel moreKeysPanel = mMoreSuggestionsView; 7817339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka final int pointX = stripWidth / 2; 7827339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka final int pointY = -params.mMoreSuggestionsBottomGap; 7837339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka moreKeysPanel.showMoreKeysPanel(this, mMoreSuggestionsController, pointX, pointY, 7847339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka mMoreSuggestionsWindow, mMoreSuggestionsListener); 7857339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka mMoreSuggestionsMode = MORE_SUGGESTIONS_CHECKING_MODAL_OR_SLIDING; 7867339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka mOriginX = mLastX; 7877339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka mOriginY = mLastY; 7887339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka mKeyboardView.dimEntireKeyboard(true); 7897339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka for (int i = 0; i < params.mSuggestionsCountInStrip; i++) { 7907339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka mWords.get(i).setPressed(false); 7917339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka } 7927339a62a1368b632c0cedaf1d876a0e8590a47edTadashi G. Takaoka return true; 793ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka } 794ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka 79550e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka // Working variables for onLongClick and dispatchTouchEvent. 796d7b00f34904c61f955e439160e2dbaa3a4b6983cTadashi G. Takaoka private int mMoreSuggestionsMode = MORE_SUGGESTIONS_IN_MODAL_MODE; 797d7b00f34904c61f955e439160e2dbaa3a4b6983cTadashi G. Takaoka private static final int MORE_SUGGESTIONS_IN_MODAL_MODE = 0; 798d7b00f34904c61f955e439160e2dbaa3a4b6983cTadashi G. Takaoka private static final int MORE_SUGGESTIONS_CHECKING_MODAL_OR_SLIDING = 1; 799d7b00f34904c61f955e439160e2dbaa3a4b6983cTadashi G. Takaoka private static final int MORE_SUGGESTIONS_IN_SLIDING_MODE = 2; 80050e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka private int mLastX; 80150e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka private int mLastY; 80250e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka private int mOriginX; 80350e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka private int mOriginY; 80450e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka private final int mMoreSuggestionsModalTolerance; 8053fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka private final GestureDetector mMoreSuggestionsSlidingDetector; 8063fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka private final GestureDetector.OnGestureListener mMoreSuggestionsSlidingListener = 8073fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka new GestureDetector.SimpleOnGestureListener() { 8083fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka @Override 8093fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka public boolean onScroll(MotionEvent down, MotionEvent me, float deltaX, float deltaY) { 8103fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka final float dy = me.getY() - down.getY(); 8113fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka if (deltaY > 0 && dy < 0) { 8123fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka return showMoreSuggestions(); 8133fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka } 8143fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka return false; 8153fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka } 8163fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka }; 81750e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka 818ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka @Override 8193e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka public boolean dispatchTouchEvent(final MotionEvent me) { 820d7b00f34904c61f955e439160e2dbaa3a4b6983cTadashi G. Takaoka if (!mMoreSuggestionsWindow.isShowing() 821d7b00f34904c61f955e439160e2dbaa3a4b6983cTadashi G. Takaoka || mMoreSuggestionsMode == MORE_SUGGESTIONS_IN_MODAL_MODE) { 82250e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka mLastX = (int)me.getX(); 82350e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka mLastY = (int)me.getY(); 8243fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka if (mMoreSuggestionsSlidingDetector.onTouchEvent(me)) { 8253fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka return true; 8263fc4ddec68b4f56f53ed6da80b5e44f38c085740Tadashi G. Takaoka } 82729e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka return super.dispatchTouchEvent(me); 82829e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka } 8298ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka 8308ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka final MoreKeysPanel moreKeysPanel = mMoreSuggestionsView; 83129e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka final int action = me.getAction(); 83229e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka final long eventTime = me.getEventTime(); 83329e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka final int index = me.getActionIndex(); 83429e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka final int id = me.getPointerId(index); 8358ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka final PointerTracker tracker = PointerTracker.getPointerTracker(id, moreKeysPanel); 8368ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka final int x = (int)me.getX(index); 8378ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka final int y = (int)me.getY(index); 8388ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka final int translatedX = moreKeysPanel.translateX(x); 8398ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka final int translatedY = moreKeysPanel.translateY(y); 8408ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka 841d7b00f34904c61f955e439160e2dbaa3a4b6983cTadashi G. Takaoka if (mMoreSuggestionsMode == MORE_SUGGESTIONS_CHECKING_MODAL_OR_SLIDING) { 84287104bace9cb9ed1a700f05a37743a21c2722fffTadashi G. Takaoka if (Math.abs(x - mOriginX) >= mMoreSuggestionsModalTolerance 84387104bace9cb9ed1a700f05a37743a21c2722fffTadashi G. Takaoka || mOriginY - y >= mMoreSuggestionsModalTolerance) { 84487104bace9cb9ed1a700f05a37743a21c2722fffTadashi G. Takaoka // Decided to be in the sliding input mode only when the touch point has been moved 84587104bace9cb9ed1a700f05a37743a21c2722fffTadashi G. Takaoka // upward. 846d7b00f34904c61f955e439160e2dbaa3a4b6983cTadashi G. Takaoka mMoreSuggestionsMode = MORE_SUGGESTIONS_IN_SLIDING_MODE; 847e51d164482c7896892d6eccb80f1e1e6fe6d50dbTadashi G. Takaoka tracker.onShowMoreKeysPanel(translatedX, translatedY, moreKeysPanel); 84850e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka } else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_POINTER_UP) { 84950e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka // Decided to be in the modal input mode 850d7b00f34904c61f955e439160e2dbaa3a4b6983cTadashi G. Takaoka mMoreSuggestionsMode = MORE_SUGGESTIONS_IN_MODAL_MODE; 85150e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka } 85250e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka return true; 85350e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka } 85450e1073e11240fe51b3baf0e2ed80dac0d9f001dTadashi G. Takaoka 855d7b00f34904c61f955e439160e2dbaa3a4b6983cTadashi G. Takaoka // MORE_SUGGESTIONS_IN_SLIDING_MODE 8568ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka tracker.processMotionEvent(action, translatedX, translatedY, eventTime, moreKeysPanel); 85729e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka return true; 85829e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka } 85929e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka 86029e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka @Override 8613e5a3c18bebbfb56012383411b24ee81ffde09cbTadashi G. Takaoka public void onClick(final View view) { 8629f763d14451685965039990891eb0bc8e8db0735Tadashi G. Takaoka if (mParams.isAddToDictionaryShowing(view)) { 8633d8e7a62fc6182c12ca28c29ceeee52ed4b9eea7Jean Chalard mListener.addWordToUserDictionary(mParams.getAddToDictionaryWord().toString()); 864717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka clear(); 865717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka return; 866717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka } 867717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka 86886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka final Object tag = view.getTag(); 86986e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka if (!(tag instanceof Integer)) 87086e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka return; 87186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka final int index = (Integer) tag; 872e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka if (index >= mSuggestedWords.size()) 87337deb112c727dfed5e94d054cf5f00f5d60c8120Tadashi G. Takaoka return; 87486e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka 875e79b1a83126b41e09a8ec0a8dbb751ae0e02c7f6Tadashi G. Takaoka final CharSequence word = mSuggestedWords.getWord(index); 8766785b9072762e15bb49657ce7b7d228dab76e44aTadashi G. Takaoka mListener.pickSuggestionManually(index, word); 877923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 87882411d47ba7e8133ed2390c6920945e139a738cesatok 8796ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani @Override 88073cd4c1428ac370e1c15c5f61b1ce499f0d4f4c7Tadashi G. Takaoka protected void onDetachedFromWindow() { 8816ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani super.onDetachedFromWindow(); 88255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka mHandler.cancelAllMessages(); 8836ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani hidePreview(); 88432f4ceb2434b6f204cf8152b406d0f9a642feb73Tadashi G. Takaoka dismissMoreSuggestions(); 8856ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani } 886923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project} 887