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