SuggestionStripView.java revision 8ac6d505b7ceab020a4085b3dfbea5b47362b030
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 17923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectpackage com.android.inputmethod.latin; 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; 226f7218627eda110a8454053f8ecb7b80edfdc8cesatokimport android.graphics.Color; 23923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.graphics.Typeface; 24e583371b13ebd9aa336d0883e8c174ae4918c758Tadashi G. Takaokaimport android.graphics.drawable.Drawable; 25e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaokaimport android.os.Message; 2629e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaokaimport android.os.SystemClock; 27522d5c16d20657e7d26009fe9c067404e16a6c2aTadashi G. Takaokaimport android.text.Spannable; 28522d5c16d20657e7d26009fe9c067404e16a6c2aTadashi G. Takaokaimport android.text.SpannableString; 29e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaokaimport android.text.Spanned; 30b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaokaimport android.text.TextPaint; 31e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaokaimport android.text.TextUtils; 3255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaokaimport android.text.style.BackgroundColorSpan; 33522d5c16d20657e7d26009fe9c067404e16a6c2aTadashi G. Takaokaimport android.text.style.CharacterStyle; 3455b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaokaimport android.text.style.ForegroundColorSpan; 3574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaokaimport android.text.style.StyleSpan; 36522d5c16d20657e7d26009fe9c067404e16a6c2aTadashi G. Takaokaimport android.text.style.UnderlineSpan; 37923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.util.AttributeSet; 38923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.Gravity; 39923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.LayoutInflater; 4029e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaokaimport android.view.MotionEvent; 41923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.View; 42e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaokaimport android.view.View.OnClickListener; 43ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaokaimport android.view.View.OnLongClickListener; 44e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaokaimport android.view.ViewGroup; 45e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaokaimport android.widget.LinearLayout; 46923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.widget.PopupWindow; 47c412309b7a32308b1b0a175dafc13f90254353c5Tadashi G. Takaokaimport android.widget.RelativeLayout; 48923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.widget.TextView; 49923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 50a7eed902f1b0d6871d416412b3c6f91163fa2578Tadashi G. Takaokaimport com.android.inputmethod.compat.FrameLayoutCompatUtils; 5129e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaokaimport com.android.inputmethod.keyboard.KeyboardActionListener; 521b087064c07975c5e2b9c17d4ca80c56e01c35c0Tadashi G. Takaokaimport com.android.inputmethod.keyboard.KeyboardView; 5329e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaokaimport com.android.inputmethod.keyboard.MoreKeysPanel; 5429e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaokaimport com.android.inputmethod.keyboard.PointerTracker; 55ddb61ea461b920d87be4ad78c8a36eec1013b965Tadashi G. Takaokaimport com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; 56ddb61ea461b920d87be4ad78c8a36eec1013b965Tadashi G. Takaoka 57179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaokaimport java.util.ArrayList; 586f7218627eda110a8454053f8ecb7b80edfdc8cesatokimport java.util.List; 59179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaoka 60c412309b7a32308b1b0a175dafc13f90254353c5Tadashi G. Takaokapublic class SuggestionsView extends RelativeLayout implements OnClickListener, 61c412309b7a32308b1b0a175dafc13f90254353c5Tadashi G. Takaoka OnLongClickListener { 62c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka public interface Listener { 63c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka public boolean addWordToDictionary(String word); 64c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka public void pickSuggestionManually(int index, CharSequence word); 65c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka } 66c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka 6786e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka // The maximum number of suggestions available. See {@link Suggest#mPrefMaxSuggestions}. 6829e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka public static final int MAX_SUGGESTIONS = 18; 69923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 708553b5ec315660ab53dd9234e64e1e39ea09ec0fJean Chalard private static final boolean DBG = LatinImeLogger.sDBG; 716f7218627eda110a8454053f8ecb7b80edfdc8cesatok 72913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka private final ViewGroup mSuggestionsStrip; 731b087064c07975c5e2b9c17d4ca80c56e01c35c0Tadashi G. Takaoka private KeyboardView mKeyboardView; 7474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 7529e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka private final View mMoreSuggestionsContainer; 7629e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka private final MoreSuggestionsView mMoreSuggestionsView; 7729e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka private final MoreSuggestions.Builder mMoreSuggestionsBuilder; 7829e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka private final PopupWindow mMoreSuggestionsWindow; 7929e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka 801e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka private final ArrayList<TextView> mWords = new ArrayList<TextView>(); 812442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka private final ArrayList<TextView> mInfos = new ArrayList<TextView>(); 82ddb61ea461b920d87be4ad78c8a36eec1013b965Tadashi G. Takaoka private final ArrayList<View> mDividers = new ArrayList<View>(); 8374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 8482411d47ba7e8133ed2390c6920945e139a738cesatok private final PopupWindow mPreviewPopup; 8582411d47ba7e8133ed2390c6920945e139a738cesatok private final TextView mPreviewText; 8666a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani 87c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka private Listener mListener; 887e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka private SuggestedWords mSuggestions = SuggestedWords.EMPTY; 8955b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka private boolean mShowingAutoCorrectionInverted; 906a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani 91d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka private final SuggestionsViewParams mParams; 92ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka private static final float MIN_TEXT_XSCALE = 0.70f; 93b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka 944f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa private final UiHandler mHandler = new UiHandler(this); 9555b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 96913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka private static class UiHandler extends StaticInnerHandlerWrapper<SuggestionsView> { 9755b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka private static final int MSG_HIDE_PREVIEW = 0; 9855b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka private static final int MSG_UPDATE_SUGGESTION = 1; 9955b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 100c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka private static final long DELAY_HIDE_PREVIEW = 1300; 10155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka private static final long DELAY_UPDATE_SUGGESTION = 300; 10255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 103913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka public UiHandler(SuggestionsView outerInstance) { 1044f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa super(outerInstance); 1054f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa } 1064f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa 107e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka @Override 108e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka public void dispatchMessage(Message msg) { 109913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka final SuggestionsView suggestionsView = getOuterInstance(); 110e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka switch (msg.what) { 111e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka case MSG_HIDE_PREVIEW: 112913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka suggestionsView.hidePreview(); 113e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka break; 11455b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka case MSG_UPDATE_SUGGESTION: 115913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka suggestionsView.updateSuggestions(); 11655b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka break; 117e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka } 118e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka } 11955b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 12055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka public void postHidePreview() { 12155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka cancelHidePreview(); 12255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka sendMessageDelayed(obtainMessage(MSG_HIDE_PREVIEW), DELAY_HIDE_PREVIEW); 12355b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka } 12455b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 12555b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka public void cancelHidePreview() { 12655b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka removeMessages(MSG_HIDE_PREVIEW); 12755b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka } 12855b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 1299fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka public void postUpdateSuggestions() { 13055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka cancelUpdateSuggestions(); 1319fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka sendMessageDelayed(obtainMessage(MSG_UPDATE_SUGGESTION), 13255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka DELAY_UPDATE_SUGGESTION); 13355b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka } 13455b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 13555b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka public void cancelUpdateSuggestions() { 13655b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka removeMessages(MSG_UPDATE_SUGGESTION); 13755b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka } 13855b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 13955b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka public void cancelAllMessages() { 14055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka cancelHidePreview(); 14155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka cancelUpdateSuggestions(); 14255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka } 143e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka } 144179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaoka 145913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka private static class SuggestionsViewParams { 146d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka private static final int DEFAULT_SUGGESTIONS_COUNT_IN_STRIP = 3; 147d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka private static final int DEFAULT_CENTER_SUGGESTION_PERCENTILE = 40; 1489676038b6e9fb66760588d7f9c9c642cc493dd71Tadashi G. Takaoka private static final int DEFAULT_MAX_MORE_SUGGESTIONS_ROW = 2; 149d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka private static final int PUNCTUATIONS_IN_STRIP = 6; 150d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka 15174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka public final int mPadding; 15274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka public final int mDividerWidth; 153913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka public final int mSuggestionsStripHeight; 154d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka public final int mSuggestionsCountInStrip; 1559676038b6e9fb66760588d7f9c9c642cc493dd71Tadashi G. Takaoka public final int mMaxMoreSuggestionsRow; 1569676038b6e9fb66760588d7f9c9c642cc493dd71Tadashi G. Takaoka public final float mMinMoreSuggestionsWidth; 15716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka 158d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka private final List<TextView> mWords; 159d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka private final List<View> mDividers; 160d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka private final List<TextView> mInfos; 161d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka 162d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka private final int mColorTypedWord; 163d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka private final int mColorAutoCorrect; 164913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka private final int mColorSuggested; 165913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka private final float mCenterSuggestionWeight; 166913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka private final int mCenterSuggestionIndex; 167913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka private final Drawable mMoreSuggestionsHint; 168d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka 169d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka private static final CharacterStyle BOLD_SPAN = new StyleSpan(Typeface.BOLD); 170d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka private static final CharacterStyle UNDERLINE_SPAN = new UnderlineSpan(); 171d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka private final CharacterStyle mInvertedForegroundColorSpan; 172d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka private final CharacterStyle mInvertedBackgroundColorSpan; 173d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka private static final int AUTO_CORRECT_BOLD = 0x01; 174d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka private static final int AUTO_CORRECT_UNDERLINE = 0x02; 175d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka private static final int AUTO_CORRECT_INVERT = 0x04; 176d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka private static final int VALID_TYPED_WORD_BOLD = 0x08; 177d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka 178d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka private final int mSuggestionStripOption; 17974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 180d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka private final ArrayList<CharSequence> mTexts = new ArrayList<CharSequence>(); 18174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 182ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka public boolean mMoreSuggestionsAvailable; 183ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka 184c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka public final TextView mWordToSaveView; 185c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka private final TextView mHintToSaveView; 186c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka private final CharSequence mHintToSaveText; 187c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka 188d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka public SuggestionsViewParams(Context context, AttributeSet attrs, int defStyle, 189ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka List<TextView> words, List<View> dividers, List<TextView> infos) { 190d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka mWords = words; 191d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka mDividers = dividers; 192d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka mInfos = infos; 193d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka 194d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka final TextView word = words.get(0); 195d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka final View divider = dividers.get(0); 196d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka mPadding = word.getCompoundPaddingLeft() + word.getCompoundPaddingRight(); 197d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka divider.measure( 198d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); 199d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka mDividerWidth = divider.getMeasuredWidth(); 200d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka 201d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka final Resources res = word.getResources(); 202d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka mSuggestionsStripHeight = res.getDimensionPixelSize(R.dimen.suggestions_strip_height); 203d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka 204d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka final TypedArray a = context.obtainStyledAttributes( 205913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka attrs, R.styleable.SuggestionsView, defStyle, R.style.SuggestionsViewStyle); 206913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka mSuggestionStripOption = a.getInt(R.styleable.SuggestionsView_suggestionStripOption, 0); 207913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka mColorTypedWord = a.getColor(R.styleable.SuggestionsView_colorTypedWord, 0); 208913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka mColorAutoCorrect = a.getColor(R.styleable.SuggestionsView_colorAutoCorrect, 0); 209913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka mColorSuggested = a.getColor(R.styleable.SuggestionsView_colorSuggested, 0); 210913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka mSuggestionsCountInStrip = a.getInt( 211913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka R.styleable.SuggestionsView_suggestionsCountInStrip, 212913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka DEFAULT_SUGGESTIONS_COUNT_IN_STRIP); 213913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka mCenterSuggestionWeight = a.getInt( 214913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka R.styleable.SuggestionsView_centerSuggestionPercentile, 215913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka DEFAULT_CENTER_SUGGESTION_PERCENTILE) / 100.0f; 2169676038b6e9fb66760588d7f9c9c642cc493dd71Tadashi G. Takaoka mMaxMoreSuggestionsRow = a.getInt( 2179676038b6e9fb66760588d7f9c9c642cc493dd71Tadashi G. Takaoka R.styleable.SuggestionsView_maxMoreSuggestionsRow, 2189676038b6e9fb66760588d7f9c9c642cc493dd71Tadashi G. Takaoka DEFAULT_MAX_MORE_SUGGESTIONS_ROW); 2199676038b6e9fb66760588d7f9c9c642cc493dd71Tadashi G. Takaoka mMinMoreSuggestionsWidth = getRatio(a, 2209676038b6e9fb66760588d7f9c9c642cc493dd71Tadashi G. Takaoka R.styleable.SuggestionsView_minMoreSuggestionsWidth); 221d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka a.recycle(); 222d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka 223913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka mCenterSuggestionIndex = mSuggestionsCountInStrip / 2; 224913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka mMoreSuggestionsHint = res.getDrawable(R.drawable.more_suggestions_hint); 22560a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka 226d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka mInvertedForegroundColorSpan = new ForegroundColorSpan(mColorTypedWord ^ 0x00ffffff); 227d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka mInvertedBackgroundColorSpan = new BackgroundColorSpan(mColorTypedWord); 228d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka 229c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka final LayoutInflater inflater = LayoutInflater.from(context); 230913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka mWordToSaveView = (TextView)inflater.inflate(R.layout.suggestion_word, null); 231913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka mHintToSaveView = (TextView)inflater.inflate(R.layout.suggestion_word, null); 232c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka mHintToSaveText = context.getText(R.string.hint_add_to_dictionary); 23374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka } 23474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 2359676038b6e9fb66760588d7f9c9c642cc493dd71Tadashi G. Takaoka // Read fraction value in TypedArray as float. 2369676038b6e9fb66760588d7f9c9c642cc493dd71Tadashi G. Takaoka private static float getRatio(TypedArray a, int index) { 2379676038b6e9fb66760588d7f9c9c642cc493dd71Tadashi G. Takaoka return a.getFraction(index, 1000, 1000, 1) / 1000.0f; 2389676038b6e9fb66760588d7f9c9c642cc493dd71Tadashi G. Takaoka } 2399676038b6e9fb66760588d7f9c9c642cc493dd71Tadashi G. Takaoka 240913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka private CharSequence getStyledSuggestionWord(SuggestedWords suggestions, int pos) { 241d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka final CharSequence word = suggestions.getWord(pos); 242d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka final boolean isAutoCorrect = pos == 1 && willAutoCorrect(suggestions); 243d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka final boolean isTypedWordValid = pos == 0 && suggestions.mTypedWordValid; 244d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka if (!isAutoCorrect && !isTypedWordValid) 245d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka return word; 246d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka 247d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka final int len = word.length(); 248d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka final Spannable spannedWord = new SpannableString(word); 249d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka final int option = mSuggestionStripOption; 250d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka if ((isAutoCorrect && (option & AUTO_CORRECT_BOLD) != 0) 251d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka || (isTypedWordValid && (option & VALID_TYPED_WORD_BOLD) != 0)) { 252d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka spannedWord.setSpan(BOLD_SPAN, 0, len, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); 253d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka } 254d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka if (isAutoCorrect && (option & AUTO_CORRECT_UNDERLINE) != 0) { 255d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka spannedWord.setSpan(UNDERLINE_SPAN, 0, len, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); 256d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka } 257d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka return spannedWord; 258d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka } 259d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka 26060a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka private static boolean willAutoCorrect(SuggestedWords suggestions) { 26160a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka return !suggestions.mTypedWordValid && suggestions.mHasMinimalSuggestion; 26260a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka } 26360a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka 26460a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka private int getWordPosition(int index, SuggestedWords suggestions) { 26560a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka // TODO: This works for 3 suggestions. Revisit this algorithm when there are 5 or more 26660a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka // suggestions. 26760a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka final int centerPos = willAutoCorrect(suggestions) ? 1 : 0; 268913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka if (index == mCenterSuggestionIndex) { 26960a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka return centerPos; 27060a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka } else if (index == centerPos) { 271913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka return mCenterSuggestionIndex; 27260a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka } else { 273d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka return index; 274d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka } 275d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka } 276d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka 277913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka private int getSuggestionTextColor(int index, SuggestedWords suggestions, int pos) { 278d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka // TODO: Need to revisit this logic with bigram suggestions 279913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka final boolean isSuggested = (pos != 0); 280d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka 281d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka final int color; 282913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka if (index == mCenterSuggestionIndex && willAutoCorrect(suggestions)) { 283d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka color = mColorAutoCorrect; 284913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka } else if (isSuggested) { 285913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka color = mColorSuggested; 286d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka } else { 287d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka color = mColorTypedWord; 288d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka } 28960a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka 29060a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka final SuggestedWordInfo info = (pos < suggestions.size()) 29160a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka ? suggestions.getInfo(pos) : null; 292add3e053797d7d2355c61160ab746f7dfeb92aefsatok if (info != null && info.isObsoleteSuggestedWord()) { 293d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka return applyAlpha(color, 0.5f); 294d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka } else { 295d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka return color; 296d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka } 297d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka } 298d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka 299d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka private static int applyAlpha(final int color, final float alpha) { 300d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka final int newAlpha = (int)(Color.alpha(color) * alpha); 301d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka return Color.argb(newAlpha, Color.red(color), Color.green(color), Color.blue(color)); 302d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka } 303d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka 304d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka public CharSequence getInvertedText(CharSequence text) { 305d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka if ((mSuggestionStripOption & AUTO_CORRECT_INVERT) == 0) 306d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka return null; 307d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka final int len = text.length(); 308d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka final Spannable word = new SpannableString(text); 309d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka word.setSpan(mInvertedBackgroundColorSpan, 0, len, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); 310d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka word.setSpan(mInvertedForegroundColorSpan, 0, len, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); 311d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka return word; 312d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka } 313d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka 3143a566c48b0eb3625788e1cce3fb2f58d8f4b380dTadashi G. Takaoka public void layout(SuggestedWords suggestions, ViewGroup stripView, ViewGroup placer, 31516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka int stripWidth) { 31660a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka if (suggestions.isPunctuationSuggestions()) { 3173a566c48b0eb3625788e1cce3fb2f58d8f4b380dTadashi G. Takaoka layoutPunctuationSuggestions(suggestions, stripView); 3183a566c48b0eb3625788e1cce3fb2f58d8f4b380dTadashi G. Takaoka return; 31960a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka } 32060a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka 321913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka final int countInStrip = mSuggestionsCountInStrip; 32260a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka setupTexts(suggestions, countInStrip); 323bbf25cf25169f640a361370cde5521ffc7789a1bKen Wakasa mMoreSuggestionsAvailable = (suggestions.size() > countInStrip); 32460a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka int x = 0; 32560a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka for (int index = 0; index < countInStrip; index++) { 32660a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka final int pos = getWordPosition(index, suggestions); 32760a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka 32860a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka if (index != 0) { 32960a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka final View divider = mDividers.get(pos); 330913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka // Add divider if this isn't the left most suggestion in suggestions strip. 33160a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka stripView.addView(divider); 332013ba3e3e785980b74db83ac5ab1e11b438485daTadashi G. Takaoka x += divider.getMeasuredWidth(); 33360a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka } 33460a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka 33516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka final CharSequence styled = mTexts.get(pos); 33660a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka final TextView word = mWords.get(pos); 337913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka if (index == mCenterSuggestionIndex && mMoreSuggestionsAvailable) { 338ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka // TODO: This "more suggestions hint" should have nicely designed icon. 339ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka word.setCompoundDrawablesWithIntrinsicBounds( 340913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka null, null, null, mMoreSuggestionsHint); 341580e1d7ac0cb90a464a3b3aed88047f85a4ab41fTadashi G. Takaoka // HACK: To align with other TextView that has no compound drawables. 342913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka word.setCompoundDrawablePadding(-mMoreSuggestionsHint.getIntrinsicHeight()); 343ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka } else { 344580e1d7ac0cb90a464a3b3aed88047f85a4ab41fTadashi G. Takaoka word.setCompoundDrawablesWithIntrinsicBounds(null, null, null, null); 345ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka } 346ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka 347913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka // Disable this suggestion if the suggestion is null or empty. 34860a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka word.setEnabled(!TextUtils.isEmpty(styled)); 349913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka word.setTextColor(getSuggestionTextColor(index, suggestions, pos)); 350913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka final int width = getSuggestionWidth(index, stripWidth); 35160a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka final CharSequence text = getEllipsizedText(styled, width, word.getPaint()); 35260a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka final float scaleX = word.getTextScaleX(); 35360a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka word.setText(text); // TextView.setText() resets text scale x to 1.0. 35460a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka word.setTextScaleX(scaleX); 35560a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka stripView.addView(word); 356b8dc67466339dc14653ad634c86851025373326bTadashi G. Takaoka setLayoutWeight( 357913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka word, getSuggestionWeight(index), ViewGroup.LayoutParams.MATCH_PARENT); 358013ba3e3e785980b74db83ac5ab1e11b438485daTadashi G. Takaoka x += word.getMeasuredWidth(); 35916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka 36016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka if (DBG) { 36160a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka final CharSequence debugInfo = getDebugInfo(suggestions, pos); 36216713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka if (debugInfo != null) { 36360a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka final TextView info = mInfos.get(pos); 36416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka info.setText(debugInfo); 365013ba3e3e785980b74db83ac5ab1e11b438485daTadashi G. Takaoka placer.addView(info); 366b8dc67466339dc14653ad634c86851025373326bTadashi G. Takaoka info.measure(ViewGroup.LayoutParams.WRAP_CONTENT, 367b8dc67466339dc14653ad634c86851025373326bTadashi G. Takaoka ViewGroup.LayoutParams.WRAP_CONTENT); 36860a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka final int infoWidth = info.getMeasuredWidth(); 36916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka final int y = info.getMeasuredHeight(); 370013ba3e3e785980b74db83ac5ab1e11b438485daTadashi G. Takaoka FrameLayoutCompatUtils.placeViewAt( 371013ba3e3e785980b74db83ac5ab1e11b438485daTadashi G. Takaoka info, x - infoWidth, y, infoWidth, info.getMeasuredHeight()); 37216713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka } 37360a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka } 37416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka } 37516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka } 37616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka 377913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka private int getSuggestionWidth(int index, int maxWidth) { 378913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka final int paddings = mPadding * mSuggestionsCountInStrip; 379913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka final int dividers = mDividerWidth * (mSuggestionsCountInStrip - 1); 38060a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka final int availableWidth = maxWidth - paddings - dividers; 381913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka return (int)(availableWidth * getSuggestionWeight(index)); 38260a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka } 38374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 384913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka private float getSuggestionWeight(int index) { 385913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka if (index == mCenterSuggestionIndex) { 386913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka return mCenterSuggestionWeight; 38760a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka } else { 38860a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka // TODO: Revisit this for cases of 5 or more suggestions 389913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka return (1.0f - mCenterSuggestionWeight) / (mSuggestionsCountInStrip - 1); 39074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka } 39174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka } 39274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 39360a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka private void setupTexts(SuggestedWords suggestions, int countInStrip) { 39474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mTexts.clear(); 39560a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka final int count = Math.min(suggestions.size(), countInStrip); 39660a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka for (int pos = 0; pos < count; pos++) { 397913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka final CharSequence styled = getStyledSuggestionWord(suggestions, pos); 39874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka mTexts.add(styled); 39974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka } 40060a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka for (int pos = count; pos < countInStrip; pos++) { 40160a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka // Make this inactive for touches in layout(). 40260a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka mTexts.add(null); 40360a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka } 40474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka } 40574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 4063a566c48b0eb3625788e1cce3fb2f58d8f4b380dTadashi G. Takaoka private void layoutPunctuationSuggestions(SuggestedWords suggestions, ViewGroup stripView) { 40760a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka final int countInStrip = Math.min(suggestions.size(), PUNCTUATIONS_IN_STRIP); 40860a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka for (int index = 0; index < countInStrip; index++) { 40960a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka if (index != 0) { 410913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka // Add divider if this isn't the left most suggestion in suggestions strip. 41160a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka stripView.addView(mDividers.get(index)); 41260a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka } 41360a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka 41460a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka final TextView word = mWords.get(index); 41560a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka word.setEnabled(true); 41660a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka word.setTextColor(mColorTypedWord); 41760a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka final CharSequence text = suggestions.getWord(index); 41860a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka word.setText(text); 41960a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka word.setTextScaleX(1.0f); 420ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka word.setCompoundDrawables(null, null, null, null); 42160a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka stripView.addView(word); 422913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka setLayoutWeight(word, 1.0f, mSuggestionsStripHeight); 42360a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka } 424ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka mMoreSuggestionsAvailable = false; 42574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka } 426c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka 427c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka public void layoutAddToDictionaryHint(CharSequence word, ViewGroup stripView, 428c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka int stripWidth) { 429c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka final int width = stripWidth - mDividerWidth - mPadding * 2; 430c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka 431c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka final TextView wordView = mWordToSaveView; 432c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka wordView.setTextColor(mColorTypedWord); 433913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka final int wordWidth = (int)(width * mCenterSuggestionWeight); 434c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka final CharSequence text = getEllipsizedText(word, wordWidth, wordView.getPaint()); 435c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka final float wordScaleX = wordView.getTextScaleX(); 436c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka wordView.setTag(word); 437c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka wordView.setText(text); 438c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka wordView.setTextScaleX(wordScaleX); 439c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka stripView.addView(wordView); 440913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka setLayoutWeight(wordView, mCenterSuggestionWeight, ViewGroup.LayoutParams.MATCH_PARENT); 441c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka 442c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka stripView.addView(mDividers.get(0)); 443c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka 444c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka final TextView hintView = mHintToSaveView; 445c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka hintView.setTextColor(mColorAutoCorrect); 446c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka final int hintWidth = width - wordWidth; 447c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka final float hintScaleX = getTextScaleX(mHintToSaveText, hintWidth, hintView.getPaint()); 448c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka hintView.setText(mHintToSaveText); 449c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka hintView.setTextScaleX(hintScaleX); 450c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka stripView.addView(hintView); 451b8dc67466339dc14653ad634c86851025373326bTadashi G. Takaoka setLayoutWeight( 452913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka hintView, 1.0f - mCenterSuggestionWeight, ViewGroup.LayoutParams.MATCH_PARENT); 453c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka } 45474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka } 45574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 456923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 457913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka * Construct a {@link SuggestionsView} for showing suggested words for completion. 458923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * @param context 459923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * @param attrs 460923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 461913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka public SuggestionsView(Context context, AttributeSet attrs) { 462913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka this(context, attrs, R.attr.suggestionsViewStyle); 46308a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka } 46408a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka 465913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka public SuggestionsView(Context context, AttributeSet attrs, int defStyle) { 466c412309b7a32308b1b0a175dafc13f90254353c5Tadashi G. Takaoka super(context, attrs, defStyle); 467923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 46816713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka final LayoutInflater inflater = LayoutInflater.from(context); 469913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka inflater.inflate(R.layout.suggestions_strip, this); 47086e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka 47186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka mPreviewPopup = new PopupWindow(context); 472913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka mPreviewText = (TextView) inflater.inflate(R.layout.suggestion_preview, null); 473b8dc67466339dc14653ad634c86851025373326bTadashi G. Takaoka mPreviewPopup.setWindowLayoutMode( 474b8dc67466339dc14653ad634c86851025373326bTadashi G. Takaoka ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); 475923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project mPreviewPopup.setContentView(mPreviewText); 476923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project mPreviewPopup.setBackgroundDrawable(null); 477923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 478913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka mSuggestionsStrip = (ViewGroup)findViewById(R.id.suggestions_strip); 47960a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka for (int pos = 0; pos < MAX_SUGGESTIONS; pos++) { 480913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka final TextView word = (TextView)inflater.inflate(R.layout.suggestion_word, null); 48160a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka word.setTag(pos); 4822442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka word.setOnClickListener(this); 483ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka word.setOnLongClickListener(this); 4842442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka mWords.add(word); 485913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka final View divider = inflater.inflate(R.layout.suggestion_divider, null); 48660a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka divider.setTag(pos); 487a1aab83a24e74cb0fad4b1c1e59b18d23ecbdad3Tadashi G. Takaoka divider.setOnClickListener(this); 488a1aab83a24e74cb0fad4b1c1e59b18d23ecbdad3Tadashi G. Takaoka mDividers.add(divider); 489913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka mInfos.add((TextView)inflater.inflate(R.layout.suggestion_info, null)); 490c9716b28ce438e06b5cacc07fc002944bcbe24a0Tadashi G. Takaoka } 491179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaoka 492d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka mParams = new SuggestionsViewParams(context, attrs, defStyle, mWords, mDividers, mInfos); 493d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka mParams.mWordToSaveView.setOnClickListener(this); 49429e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka 49529e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka mMoreSuggestionsContainer = inflater.inflate(R.layout.more_suggestions, null); 49629e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka mMoreSuggestionsView = (MoreSuggestionsView)mMoreSuggestionsContainer 49729e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka .findViewById(R.id.more_suggestions_view); 49829e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka mMoreSuggestionsBuilder = new MoreSuggestions.Builder(mMoreSuggestionsView); 49929e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka mMoreSuggestionsWindow = new PopupWindow(context); 50029e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka mMoreSuggestionsWindow.setWindowLayoutMode( 50129e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); 50229e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka mMoreSuggestionsWindow.setBackgroundDrawable(null); 503923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 504c9716b28ce438e06b5cacc07fc002944bcbe24a0Tadashi G. Takaoka 505923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project /** 506c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka * A connection back to the input method. 507923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * @param listener 508923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 50986e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka public void setListener(Listener listener, View inputView) { 510c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka mListener = listener; 5111b087064c07975c5e2b9c17d4ca80c56e01c35c0Tadashi G. Takaoka mKeyboardView = (KeyboardView)inputView.findViewById(R.id.keyboard_view); 512923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 513923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 5147e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka public void setSuggestions(SuggestedWords suggestions) { 5159fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka if (suggestions == null) 516a15e45ef45931ba46678b39c159518d8aa2d4d65Tadashi G. Takaoka return; 5179fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka mSuggestions = suggestions; 51855b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka if (mShowingAutoCorrectionInverted) { 5199fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka mHandler.postUpdateSuggestions(); 52055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka } else { 5219fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka updateSuggestions(); 52255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka } 52355b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka } 52455b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 5259fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka private void updateSuggestions() { 526e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka clear(); 52716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka if (mSuggestions.size() == 0) 52874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka return; 52974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 530c412309b7a32308b1b0a175dafc13f90254353c5Tadashi G. Takaoka mParams.layout(mSuggestions, mSuggestionsStrip, this, getWidth()); 53116713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka } 53274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 53316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka private static CharSequence getDebugInfo(SuggestedWords suggestions, int pos) { 53460a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka if (DBG && pos < suggestions.size()) { 53516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka final SuggestedWordInfo wordInfo = suggestions.getInfo(pos); 53616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka if (wordInfo != null) { 53716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka final CharSequence debugInfo = wordInfo.getDebugString(); 53816713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka if (!TextUtils.isEmpty(debugInfo)) { 53916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka return debugInfo; 540d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka } 5412442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka } 54286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka } 54316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka return null; 54486e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka } 54586e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka 5463118277dd47492089761c0ed1097abaeb376395cTadashi G. Takaoka private static void setLayoutWeight(View v, float weight, int height) { 54774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka final ViewGroup.LayoutParams lp = v.getLayoutParams(); 54874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka if (lp instanceof LinearLayout.LayoutParams) { 54974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka final LinearLayout.LayoutParams llp = (LinearLayout.LayoutParams)lp; 55074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka llp.weight = weight; 55174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka llp.width = 0; 5523118277dd47492089761c0ed1097abaeb376395cTadashi G. Takaoka llp.height = height; 55374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka } 55474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka } 55574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 556c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka private static float getTextScaleX(CharSequence text, int maxWidth, TextPaint paint) { 557c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka paint.setTextScaleX(1.0f); 558c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka final int width = getTextWidth(text, paint); 559c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka if (width <= maxWidth) { 560c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka return 1.0f; 561c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka } 562c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka return maxWidth / (float)width; 563c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka } 564c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka 56574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka private static CharSequence getEllipsizedText(CharSequence text, int maxWidth, 56674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka TextPaint paint) { 5675cb10f78ed5c0e17798ea5300d8291b613c5e2a9Tadashi G. Takaoka if (text == null) return null; 56874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka paint.setTextScaleX(1.0f); 56974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka final int width = getTextWidth(text, paint); 57060a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka if (width <= maxWidth) { 57160a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka return text; 57260a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka } 57360a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka final float scaleX = maxWidth / (float)width; 574b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka if (scaleX >= MIN_TEXT_XSCALE) { 57574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka paint.setTextScaleX(scaleX); 57674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka return text; 577b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka } 578b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka 57974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka // Note that TextUtils.ellipsize() use text-x-scale as 1.0 if ellipsize is needed. To get 58060a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka // squeezed and ellipsized text, passes enlarged width (maxWidth / MIN_TEXT_XSCALE). 58174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka final CharSequence ellipsized = TextUtils.ellipsize( 58274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka text, paint, maxWidth / MIN_TEXT_XSCALE, TextUtils.TruncateAt.MIDDLE); 58374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka paint.setTextScaleX(MIN_TEXT_XSCALE); 58474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka return ellipsized; 585b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka } 586b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka 58774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka private static int getTextWidth(CharSequence text, TextPaint paint) { 588b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka if (TextUtils.isEmpty(text)) return 0; 589fe9b65afa84530d17dd82c770c19de763a50cb58Tadashi G. Takaoka final Typeface savedTypeface = paint.getTypeface(); 59074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka paint.setTypeface(getTextTypeface(text)); 591b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka final int len = text.length(); 592b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka final float[] widths = new float[len]; 593b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka final int count = paint.getTextWidths(text, 0, len, widths); 594fe9b65afa84530d17dd82c770c19de763a50cb58Tadashi G. Takaoka int width = 0; 595b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka for (int i = 0; i < count; i++) { 596fe9b65afa84530d17dd82c770c19de763a50cb58Tadashi G. Takaoka width += Math.round(widths[i] + 0.5f); 597b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka } 598fe9b65afa84530d17dd82c770c19de763a50cb58Tadashi G. Takaoka paint.setTypeface(savedTypeface); 599fe9b65afa84530d17dd82c770c19de763a50cb58Tadashi G. Takaoka return width; 600b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka } 601b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka 60274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka private static Typeface getTextTypeface(CharSequence text) { 60374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka if (!(text instanceof SpannableString)) 60474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka return Typeface.DEFAULT; 60574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 60674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka final SpannableString ss = (SpannableString)text; 60774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka final StyleSpan[] styles = ss.getSpans(0, text.length(), StyleSpan.class); 60874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka if (styles.length == 0) 60974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka return Typeface.DEFAULT; 61074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka 61174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka switch (styles[0].getStyle()) { 61274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka case Typeface.BOLD: return Typeface.DEFAULT_BOLD; 61374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka // TODO: BOLD_ITALIC, ITALIC case? 61474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka default: return Typeface.DEFAULT; 615b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka } 616b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka } 617b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka 61855b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka public void onAutoCorrectionInverted(CharSequence autoCorrectedWord) { 619d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka final CharSequence inverted = mParams.getInvertedText(autoCorrectedWord); 620d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka if (inverted == null) 62155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka return; 6221e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka final TextView tv = mWords.get(1); 623d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka tv.setText(inverted); 62455b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka mShowingAutoCorrectionInverted = true; 62555b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka } 62655b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka 627b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani public boolean isShowingAddToDictionaryHint() { 628913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka return mSuggestionsStrip.getChildCount() > 0 629d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka && mSuggestionsStrip.getChildAt(0) == mParams.mWordToSaveView; 630b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani } 631b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani 63266a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani public void showAddToDictionaryHint(CharSequence word) { 633c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka clear(); 634d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka mParams.layoutAddToDictionaryHint(word, mSuggestionsStrip, getWidth()); 63566a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani } 63666a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani 6376558253160e2039c87f424bd814f402ecd31de3bKen Wakasa public boolean dismissAddToDictionaryHint() { 638c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka if (isShowingAddToDictionaryHint()) { 639c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka clear(); 640c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka return true; 641c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka } 642c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka return false; 6436558253160e2039c87f424bd814f402ecd31de3bKen Wakasa } 6446558253160e2039c87f424bd814f402ecd31de3bKen Wakasa 6457e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka public SuggestedWords getSuggestions() { 646979f8690967ff5409fe18f5085858ccdb8e0ccf1satok return mSuggestions; 647979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 648979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 649923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project public void clear() { 65055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka mShowingAutoCorrectionInverted = false; 651913e2aeef26f172d500a4ebfc644b5f47778841aTadashi G. Takaoka mSuggestionsStrip.removeAllViews(); 652c412309b7a32308b1b0a175dafc13f90254353c5Tadashi G. Takaoka removeAllViews(); 653c412309b7a32308b1b0a175dafc13f90254353c5Tadashi G. Takaoka addView(mSuggestionsStrip); 6541b087064c07975c5e2b9c17d4ca80c56e01c35c0Tadashi G. Takaoka dismissMoreSuggestions(); 655923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 656923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 6576ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani private void hidePreview() { 658179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaoka mPreviewPopup.dismiss(); 6596ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani } 660e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka 661c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka private void showPreview(View view, CharSequence word) { 662e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka if (TextUtils.isEmpty(word)) 663e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka return; 664e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka 665e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka final TextView previewText = mPreviewText; 666d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka previewText.setTextColor(mParams.mColorTypedWord); 667e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka previewText.setText(word); 668b8dc67466339dc14653ad634c86851025373326bTadashi G. Takaoka previewText.measure( 669b8dc67466339dc14653ad634c86851025373326bTadashi G. Takaoka ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); 670e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka final int[] offsetInWindow = new int[2]; 671c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka view.getLocationInWindow(offsetInWindow); 672e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka final int posX = offsetInWindow[0]; 673e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka final int posY = offsetInWindow[1] - previewText.getMeasuredHeight(); 674e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka final PopupWindow previewPopup = mPreviewPopup; 675e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka if (previewPopup.isShowing()) { 676e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka previewPopup.update(posX, posY, previewPopup.getWidth(), previewPopup.getHeight()); 677e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka } else { 678e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka previewPopup.showAtLocation(this, Gravity.NO_GRAVITY, posX, posY); 679923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 680e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka previewText.setVisibility(VISIBLE); 68155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka mHandler.postHidePreview(); 682923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 683fcba53ef7c874a4685c12c01404c91b779cae1e8Tadashi G. Takaoka 684e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka private void addToDictionary(CharSequence word) { 685c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka if (mListener.addWordToDictionary(word.toString())) { 686c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka final CharSequence message = getContext().getString(R.string.added_word, word); 687d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka showPreview(mParams.mWordToSaveView, message); 688e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka } 689e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka } 690e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka 69129e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka private final KeyboardActionListener mMoreSuggestionsListener = 69229e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka new KeyboardActionListener.Adapter() { 69329e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka @Override 69429e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka public boolean onCustomRequest(int requestCode) { 69529e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka final int index = requestCode; 69629e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka final CharSequence word = mSuggestions.getWord(index); 69729e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka mListener.pickSuggestionManually(index, word); 6981b087064c07975c5e2b9c17d4ca80c56e01c35c0Tadashi G. Takaoka dismissMoreSuggestions(); 69929e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka return true; 70029e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka } 70129e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka 70229e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka @Override 70329e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka public void onCancelInput() { 7041b087064c07975c5e2b9c17d4ca80c56e01c35c0Tadashi G. Takaoka dismissMoreSuggestions(); 70529e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka } 70629e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka }; 70729e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka 70829e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka private final MoreKeysPanel.Controller mMoreSuggestionsController = 70929e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka new MoreKeysPanel.Controller() { 71029e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka @Override 71129e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka public boolean dismissMoreKeysPanel() { 7121b087064c07975c5e2b9c17d4ca80c56e01c35c0Tadashi G. Takaoka return dismissMoreSuggestions(); 71329e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka } 71429e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka }; 71529e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka 7161b087064c07975c5e2b9c17d4ca80c56e01c35c0Tadashi G. Takaoka private boolean dismissMoreSuggestions() { 7171b087064c07975c5e2b9c17d4ca80c56e01c35c0Tadashi G. Takaoka if (mMoreSuggestionsWindow.isShowing()) { 7181b087064c07975c5e2b9c17d4ca80c56e01c35c0Tadashi G. Takaoka mMoreSuggestionsWindow.dismiss(); 7191b087064c07975c5e2b9c17d4ca80c56e01c35c0Tadashi G. Takaoka mKeyboardView.dimEntireKeyboard(false); 7201b087064c07975c5e2b9c17d4ca80c56e01c35c0Tadashi G. Takaoka return true; 7211b087064c07975c5e2b9c17d4ca80c56e01c35c0Tadashi G. Takaoka } 7221b087064c07975c5e2b9c17d4ca80c56e01c35c0Tadashi G. Takaoka return false; 7231b087064c07975c5e2b9c17d4ca80c56e01c35c0Tadashi G. Takaoka } 7241b087064c07975c5e2b9c17d4ca80c56e01c35c0Tadashi G. Takaoka 725e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka @Override 726ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka public boolean onLongClick(View view) { 727d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka final SuggestionsViewParams params = mParams; 72829e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka if (params.mMoreSuggestionsAvailable) { 72929e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka final int stripWidth = getWidth(); 73029e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka final View container = mMoreSuggestionsContainer; 73129e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka final int maxWidth = stripWidth - container.getPaddingLeft() 73229e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka - container.getPaddingRight(); 73329e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka final MoreSuggestions.Builder builder = mMoreSuggestionsBuilder; 7349676038b6e9fb66760588d7f9c9c642cc493dd71Tadashi G. Takaoka builder.layout(mSuggestions, params.mSuggestionsCountInStrip, maxWidth, 7359676038b6e9fb66760588d7f9c9c642cc493dd71Tadashi G. Takaoka (int)(maxWidth * params.mMinMoreSuggestionsWidth), 7369676038b6e9fb66760588d7f9c9c642cc493dd71Tadashi G. Takaoka params.mMaxMoreSuggestionsRow); 73729e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka mMoreSuggestionsView.setKeyboard(builder.build()); 73829e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka container.measure( 73929e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); 74029e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka 74129e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka final MoreKeysPanel moreKeysPanel = mMoreSuggestionsView; 74229e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka final int pointX = stripWidth / 2; 74329e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka final int pointY = 0; 74429e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka moreKeysPanel.showMoreKeysPanel( 74529e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka this, mMoreSuggestionsController, pointX, pointY, 74629e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka mMoreSuggestionsWindow, mMoreSuggestionsListener); 74729e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka // TODO: Should figure out how to select the pointer tracker correctly. 74829e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka final PointerTracker tracker = PointerTracker.getPointerTracker(0, moreKeysPanel); 74929e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka final int translatedX = moreKeysPanel.translateX(tracker.getLastX()); 75029e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka final int translatedY = moreKeysPanel.translateY(tracker.getLastY()); 75129e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka tracker.onShowMoreKeysPanel( 75229e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka translatedX, translatedY, SystemClock.uptimeMillis(), moreKeysPanel); 75329e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka view.setPressed(false); 7541b087064c07975c5e2b9c17d4ca80c56e01c35c0Tadashi G. Takaoka mKeyboardView.dimEntireKeyboard(true); 755ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka return true; 756ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka } 757ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka return false; 758ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka } 759ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka 760ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka @Override 76129e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka public boolean dispatchTouchEvent(MotionEvent me) { 76229e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka if (!mMoreSuggestionsWindow.isShowing()) { 76329e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka return super.dispatchTouchEvent(me); 76429e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka } 7658ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka 7668ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka final MoreKeysPanel moreKeysPanel = mMoreSuggestionsView; 76729e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka final int action = me.getAction(); 76829e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka final long eventTime = me.getEventTime(); 76929e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka final int index = me.getActionIndex(); 77029e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka final int id = me.getPointerId(index); 7718ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka final PointerTracker tracker = PointerTracker.getPointerTracker(id, moreKeysPanel); 7728ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka final int x = (int)me.getX(index); 7738ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka final int y = (int)me.getY(index); 7748ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka final int translatedX = moreKeysPanel.translateX(x); 7758ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka final int translatedY = moreKeysPanel.translateY(y); 7768ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka 7778ac6d505b7ceab020a4085b3dfbea5b47362b030Tadashi G. Takaoka tracker.processMotionEvent(action, translatedX, translatedY, eventTime, moreKeysPanel); 77829e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka return true; 77929e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka } 78029e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka 78129e7b7ed6ef88c3e10cc6469801fef87241c9cb5Tadashi G. Takaoka @Override 782e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka public void onClick(View view) { 783d3e50a2acf04638f09786c487326f2c09e738f32Tadashi G. Takaoka if (view == mParams.mWordToSaveView) { 784c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka addToDictionary((CharSequence)view.getTag()); 785717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka clear(); 786717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka return; 787717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka } 788717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka 78986e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka final Object tag = view.getTag(); 79086e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka if (!(tag instanceof Integer)) 79186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka return; 79286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka final int index = (Integer) tag; 79337deb112c727dfed5e94d054cf5f00f5d60c8120Tadashi G. Takaoka if (index >= mSuggestions.size()) 79437deb112c727dfed5e94d054cf5f00f5d60c8120Tadashi G. Takaoka return; 79586e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka 79637deb112c727dfed5e94d054cf5f00f5d60c8120Tadashi G. Takaoka final CharSequence word = mSuggestions.getWord(index); 797717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka mListener.pickSuggestionManually(index, word); 798923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 79982411d47ba7e8133ed2390c6920945e139a738cesatok 8006ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani @Override 8016ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani public void onDetachedFromWindow() { 8026ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani super.onDetachedFromWindow(); 80355b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka mHandler.cancelAllMessages(); 8046ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani hidePreview(); 8056ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani } 806923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project} 807