SuggestionStripView.java revision c04bbc1ae9be81d25a356407c27a8e7fa22028bf
1923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project/*
2e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka * Copyright (C) 2010 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;
26522d5c16d20657e7d26009fe9c067404e16a6c2aTadashi G. Takaokaimport android.text.Spannable;
27522d5c16d20657e7d26009fe9c067404e16a6c2aTadashi G. Takaokaimport android.text.SpannableString;
28e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaokaimport android.text.Spanned;
29b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaokaimport android.text.TextPaint;
30e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaokaimport android.text.TextUtils;
3155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaokaimport android.text.style.BackgroundColorSpan;
32522d5c16d20657e7d26009fe9c067404e16a6c2aTadashi G. Takaokaimport android.text.style.CharacterStyle;
3355b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaokaimport android.text.style.ForegroundColorSpan;
3474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaokaimport android.text.style.StyleSpan;
35522d5c16d20657e7d26009fe9c067404e16a6c2aTadashi G. Takaokaimport android.text.style.UnderlineSpan;
36923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.util.AttributeSet;
37923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.Gravity;
38923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.LayoutInflater;
39923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.View;
40e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaokaimport android.view.View.OnClickListener;
41ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaokaimport android.view.View.OnLongClickListener;
42e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaokaimport android.view.ViewGroup;
43e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaokaimport android.widget.LinearLayout;
44923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.widget.PopupWindow;
45923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.widget.TextView;
46923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
47a7eed902f1b0d6871d416412b3c6f91163fa2578Tadashi G. Takaokaimport com.android.inputmethod.compat.FrameLayoutCompatUtils;
48f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaokaimport com.android.inputmethod.compat.LinearLayoutCompatUtils;
49ddb61ea461b920d87be4ad78c8a36eec1013b965Tadashi G. Takaokaimport com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
50ddb61ea461b920d87be4ad78c8a36eec1013b965Tadashi G. Takaoka
51179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaokaimport java.util.ArrayList;
526f7218627eda110a8454053f8ecb7b80edfdc8cesatokimport java.util.List;
53179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaoka
54ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaokapublic class CandidateView extends LinearLayout implements OnClickListener, OnLongClickListener {
55c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka    public interface Listener {
56c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka        public boolean addWordToDictionary(String word);
57c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka        public void pickSuggestionManually(int index, CharSequence word);
58c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka    }
59c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka
6086e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka    // The maximum number of suggestions available. See {@link Suggest#mPrefMaxSuggestions}.
6186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka    private static final int MAX_SUGGESTIONS = 18;
6274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka    private static final int WRAP_CONTENT = ViewGroup.LayoutParams.WRAP_CONTENT;
633118277dd47492089761c0ed1097abaeb376395cTadashi G. Takaoka    private static final int MATCH_PARENT = ViewGroup.LayoutParams.MATCH_PARENT;
64923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
658553b5ec315660ab53dd9234e64e1e39ea09ec0fJean Chalard    private static final boolean DBG = LatinImeLogger.sDBG;
666f7218627eda110a8454053f8ecb7b80edfdc8cesatok
6774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka    private final ViewGroup mCandidatesStrip;
6886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka    private ViewGroup mCandidatesPane;
6986e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka    private ViewGroup mCandidatesPaneContainer;
7086e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka    private View mKeyboardView;
7174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
721e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka    private final ArrayList<TextView> mWords = new ArrayList<TextView>();
732442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka    private final ArrayList<TextView> mInfos = new ArrayList<TextView>();
74ddb61ea461b920d87be4ad78c8a36eec1013b965Tadashi G. Takaoka    private final ArrayList<View> mDividers = new ArrayList<View>();
7574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
7682411d47ba7e8133ed2390c6920945e139a738cesatok    private final PopupWindow mPreviewPopup;
7782411d47ba7e8133ed2390c6920945e139a738cesatok    private final TextView mPreviewText;
7866a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani
79c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka    private Listener mListener;
807e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka    private SuggestedWords mSuggestions = SuggestedWords.EMPTY;
8155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka    private boolean mShowingAutoCorrectionInverted;
826a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani
83d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka    private final SuggestionsStripParams mStripParams;
84d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka    private final SuggestionsPaneParams mPaneParams;
85ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka    private static final float MIN_TEXT_XSCALE = 0.70f;
86b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka
874f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa    private final UiHandler mHandler = new UiHandler(this);
8855b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka
894f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa    private static class UiHandler extends StaticInnerHandlerWrapper<CandidateView> {
9055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        private static final int MSG_HIDE_PREVIEW = 0;
9155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        private static final int MSG_UPDATE_SUGGESTION = 1;
9255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka
93c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka        private static final long DELAY_HIDE_PREVIEW = 1300;
9455b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        private static final long DELAY_UPDATE_SUGGESTION = 300;
9555b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka
964f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa        public UiHandler(CandidateView outerInstance) {
974f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa            super(outerInstance);
984f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa        }
994f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa
100e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        @Override
101e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        public void dispatchMessage(Message msg) {
1024f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa            final CandidateView candidateView = getOuterInstance();
103e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka            switch (msg.what) {
104e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka            case MSG_HIDE_PREVIEW:
1054f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa                candidateView.hidePreview();
106e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka                break;
10755b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            case MSG_UPDATE_SUGGESTION:
1084f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa                candidateView.updateSuggestions();
10955b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka                break;
110e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka            }
111e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        }
11255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka
11355b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        public void postHidePreview() {
11455b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            cancelHidePreview();
11555b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            sendMessageDelayed(obtainMessage(MSG_HIDE_PREVIEW), DELAY_HIDE_PREVIEW);
11655b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        }
11755b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka
11855b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        public void cancelHidePreview() {
11955b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            removeMessages(MSG_HIDE_PREVIEW);
12055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        }
12155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka
1229fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        public void postUpdateSuggestions() {
12355b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            cancelUpdateSuggestions();
1249fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            sendMessageDelayed(obtainMessage(MSG_UPDATE_SUGGESTION),
12555b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka                    DELAY_UPDATE_SUGGESTION);
12655b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        }
12755b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka
12855b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        public void cancelUpdateSuggestions() {
12955b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            removeMessages(MSG_UPDATE_SUGGESTION);
13055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        }
13155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka
13255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        public void cancelAllMessages() {
13355b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            cancelHidePreview();
13455b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            cancelUpdateSuggestions();
13555b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        }
136e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka    }
137179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaoka
138d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka    private static class CandidateViewParams {
13974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        public final int mPadding;
14074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        public final int mDividerWidth;
14174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        public final int mDividerHeight;
14216713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka        public final int mCandidateStripHeight;
14316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka
14416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka        protected final List<TextView> mWords;
14516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka        protected final List<View> mDividers;
14616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka        protected final List<TextView> mInfos;
147d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka
14816713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka        protected CandidateViewParams(List<TextView> words, List<View> dividers,
149ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka                List<TextView> infos) {
15016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka            mWords = words;
15116713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka            mDividers = dividers;
15216713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka            mInfos = infos;
15316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka
15416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka            final TextView word = words.get(0);
15516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka            final View divider = dividers.get(0);
156d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            mPadding = word.getCompoundPaddingLeft() + word.getCompoundPaddingRight();
157d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            divider.measure(WRAP_CONTENT, MATCH_PARENT);
158d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            mDividerWidth = divider.getMeasuredWidth();
159d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            mDividerHeight = divider.getMeasuredHeight();
16016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka
16116713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka            final Resources res = word.getResources();
16216713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka            mCandidateStripHeight = res.getDimensionPixelOffset(R.dimen.candidate_strip_height);
163d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        }
164d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka    }
165d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka
166d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka    private static class SuggestionsPaneParams extends CandidateViewParams {
16716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka        public SuggestionsPaneParams(List<TextView> words, List<View> dividers,
168ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka                List<TextView> infos) {
169ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka            super(words, dividers, infos);
17016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka        }
17116713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka
17216713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka        public int layout(SuggestedWords suggestions, ViewGroup paneView, int from, int textColor,
17316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                int paneWidth) {
17416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka            final int count = Math.min(mWords.size(), suggestions.size());
17516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka            View centeringFrom = null, lastView = null;
17616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka            int x = 0, y = 0;
17716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka            for (int index = from; index < count; index++) {
17816713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                final int pos = index;
17916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                final TextView word = mWords.get(pos);
18016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                final View divider = mDividers.get(pos);
18116713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                final TextPaint paint = word.getPaint();
18216713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                word.setTextColor(textColor);
18316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                final CharSequence styled = suggestions.getWord(pos);
18416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka
18516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                final TextView info;
18616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                if (DBG) {
18716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    final CharSequence debugInfo = getDebugInfo(suggestions, index);
18816713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    if (debugInfo != null) {
18916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                        info = mInfos.get(index);
19016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                        info.setText(debugInfo);
19116713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    } else {
19216713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                        info = null;
19316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    }
19416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                } else {
19516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    info = null;
19616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                }
19716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka
19816713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                final CharSequence text;
19916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                final float scaleX;
20016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                paint.setTextScaleX(1.0f);
20116713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                final int textWidth = getTextWidth(styled, paint);
20216713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                int available = paneWidth - x - mPadding;
20316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                if (textWidth >= available) {
20416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    // Needs new row, centering previous row.
20516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    centeringCandidates(paneView, centeringFrom, lastView, x, paneWidth);
20616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    x = 0;
20716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    y += mCandidateStripHeight;
20816713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                }
20916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                if (x != 0) {
21016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    // Add divider if this isn't the left most suggestion in current row.
21116713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    paneView.addView(divider);
21216713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    FrameLayoutCompatUtils.placeViewAt(divider, x, y
21316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                            + (mCandidateStripHeight - mDividerHeight) / 2, mDividerWidth,
21416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                            mDividerHeight);
21516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    x += mDividerWidth;
21616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                }
21716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                available = paneWidth - x - mPadding;
21816713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                text = getEllipsizedText(styled, available, paint);
21916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                scaleX = paint.getTextScaleX();
22016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                word.setText(text);
22116713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                word.setTextScaleX(scaleX);
22216713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                paneView.addView(word);
22316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                lastView = word;
22416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                if (x == 0)
22516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    centeringFrom = word;
22616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                word.measure(WRAP_CONTENT,
22716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                        MeasureSpec.makeMeasureSpec(mCandidateStripHeight, MeasureSpec.EXACTLY));
22816713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                final int width = word.getMeasuredWidth();
22916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                final int height = word.getMeasuredHeight();
23016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                FrameLayoutCompatUtils.placeViewAt(word, x, y + (mCandidateStripHeight - height)
23116713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                        / 2, width, height);
23216713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                x += width;
23316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                if (info != null) {
23416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    paneView.addView(info);
23516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    lastView = info;
23616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    info.measure(WRAP_CONTENT, WRAP_CONTENT);
23716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    final int infoWidth = info.getMeasuredWidth();
23816713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    FrameLayoutCompatUtils.placeViewAt(info, x - infoWidth, y, infoWidth,
23916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                            info.getMeasuredHeight());
24016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                }
24116713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka            }
24216713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka            if (x != 0) {
24316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                // Centering last candidates row.
24416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                centeringCandidates(paneView, centeringFrom, lastView, x, paneWidth);
24516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka            }
24616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka
24716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka            return count - from;
248d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        }
249d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka    }
250d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka
251d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka    private static class SuggestionsStripParams extends CandidateViewParams {
252d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        private static final int DEFAULT_CANDIDATE_COUNT_IN_STRIP = 3;
25360a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka        private static final int DEFAULT_CENTER_CANDIDATE_PERCENTILE = 40;
254d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        private static final int PUNCTUATIONS_IN_STRIP = 6;
255d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka
256d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        private final int mColorTypedWord;
257d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        private final int mColorAutoCorrect;
258d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        private final int mColorSuggestedCandidate;
259d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        private final int mCandidateCountInStrip;
26060a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka        private final float mCenterCandidateWeight;
26160a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka        private final int mCenterCandidateIndex;
262ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka        private final Drawable mMoreCandidateHint;
263d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka
264d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        private static final CharacterStyle BOLD_SPAN = new StyleSpan(Typeface.BOLD);
265d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        private static final CharacterStyle UNDERLINE_SPAN = new UnderlineSpan();
266d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        private final CharacterStyle mInvertedForegroundColorSpan;
267d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        private final CharacterStyle mInvertedBackgroundColorSpan;
268d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        private static final int AUTO_CORRECT_BOLD = 0x01;
269d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        private static final int AUTO_CORRECT_UNDERLINE = 0x02;
270d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        private static final int AUTO_CORRECT_INVERT = 0x04;
271d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka        private static final int VALID_TYPED_WORD_BOLD = 0x08;
272d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka
273d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka        private final int mSuggestionStripOption;
27474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
275d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        private final ArrayList<CharSequence> mTexts = new ArrayList<CharSequence>();
27674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
277ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka        public boolean mMoreSuggestionsAvailable;
278ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka
279c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka        public final TextView mWordToSaveView;
280c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka        private final TextView mHintToSaveView;
281c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka        private final CharSequence mHintToSaveText;
282c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka
283d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        public SuggestionsStripParams(Context context, AttributeSet attrs, int defStyle,
284ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka                List<TextView> words, List<View> dividers, List<TextView> infos) {
285ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka            super(words, dividers, infos);
286d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            final TypedArray a = context.obtainStyledAttributes(
287d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka                    attrs, R.styleable.CandidateView, defStyle, R.style.CandidateViewStyle);
288d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka            mSuggestionStripOption = a.getInt(R.styleable.CandidateView_suggestionStripOption, 0);
289d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            mColorTypedWord = a.getColor(R.styleable.CandidateView_colorTypedWord, 0);
290d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            mColorAutoCorrect = a.getColor(R.styleable.CandidateView_colorAutoCorrect, 0);
291d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            mColorSuggestedCandidate = a.getColor(R.styleable.CandidateView_colorSuggested, 0);
292d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            mCandidateCountInStrip = a.getInt(
293d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka                    R.styleable.CandidateView_candidateCountInStrip,
294d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka                    DEFAULT_CANDIDATE_COUNT_IN_STRIP);
29560a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            mCenterCandidateWeight = a.getInt(
29660a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                    R.styleable.CandidateView_centerCandidatePercentile,
29760a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                    DEFAULT_CENTER_CANDIDATE_PERCENTILE) / 100.0f;
298d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            a.recycle();
299d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka
30060a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            mCenterCandidateIndex = mCandidateCountInStrip / 2;
301ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka            final Resources res = context.getResources();
302ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka            mMoreCandidateHint = res.getDrawable(R.drawable.more_suggestions_hint);
30360a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka
304d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            mInvertedForegroundColorSpan = new ForegroundColorSpan(mColorTypedWord ^ 0x00ffffff);
305d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            mInvertedBackgroundColorSpan = new BackgroundColorSpan(mColorTypedWord);
306d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka
307c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            final LayoutInflater inflater = LayoutInflater.from(context);
308c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            mWordToSaveView = (TextView)inflater.inflate(R.layout.candidate_word, null);
309c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            mHintToSaveView = (TextView)inflater.inflate(R.layout.candidate_word, null);
310c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            mHintToSaveText = context.getText(R.string.hint_add_to_dictionary);
31174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        }
31274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
31316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka        public int getTextColor() {
31416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka            return mColorTypedWord;
315d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        }
316d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka
317d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka        private CharSequence getStyledCandidateWord(SuggestedWords suggestions, int pos) {
318d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka            final CharSequence word = suggestions.getWord(pos);
319d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka            final boolean isAutoCorrect = pos == 1 && willAutoCorrect(suggestions);
320d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka            final boolean isTypedWordValid = pos == 0 && suggestions.mTypedWordValid;
321d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka            if (!isAutoCorrect && !isTypedWordValid)
322d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka                return word;
323d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka
324d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            final int len = word.length();
325d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            final Spannable spannedWord = new SpannableString(word);
326d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka            final int option = mSuggestionStripOption;
327d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka            if ((isAutoCorrect && (option & AUTO_CORRECT_BOLD) != 0)
328d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka                    || (isTypedWordValid && (option & VALID_TYPED_WORD_BOLD) != 0)) {
329d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka                spannedWord.setSpan(BOLD_SPAN, 0, len, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
330d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka            }
331d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka            if (isAutoCorrect && (option & AUTO_CORRECT_UNDERLINE) != 0) {
332d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka                spannedWord.setSpan(UNDERLINE_SPAN, 0, len, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
333d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka            }
334d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            return spannedWord;
335d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        }
336d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka
33760a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka        private static boolean willAutoCorrect(SuggestedWords suggestions) {
33860a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            return !suggestions.mTypedWordValid && suggestions.mHasMinimalSuggestion;
33960a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka        }
34060a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka
34160a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka        private int getWordPosition(int index, SuggestedWords suggestions) {
34260a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            // TODO: This works for 3 suggestions. Revisit this algorithm when there are 5 or more
34360a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            // suggestions.
34460a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            final int centerPos = willAutoCorrect(suggestions) ? 1 : 0;
34560a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            if (index == mCenterCandidateIndex) {
34660a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                return centerPos;
34760a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            } else if (index == centerPos) {
34860a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                return mCenterCandidateIndex;
34960a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            } else {
350d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka                return index;
351d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            }
352d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        }
353d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka
35460a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka        private int getCandidateTextColor(int index, SuggestedWords suggestions, int pos) {
355d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            // TODO: Need to revisit this logic with bigram suggestions
356d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            final boolean isSuggestedCandidate = (pos != 0);
357d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka
358d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            final int color;
35960a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            if (index == mCenterCandidateIndex && willAutoCorrect(suggestions)) {
360d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka                color = mColorAutoCorrect;
361d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            } else if (isSuggestedCandidate) {
362d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka                color = mColorSuggestedCandidate;
363d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            } else {
364d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka                color = mColorTypedWord;
365d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            }
36660a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka
36760a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            final SuggestedWordInfo info = (pos < suggestions.size())
36860a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                    ? suggestions.getInfo(pos) : null;
369d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            if (info != null && info.isPreviousSuggestedWord()) {
370d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka                return applyAlpha(color, 0.5f);
371d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            } else {
372d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka                return color;
373d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            }
374d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        }
375d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka
376d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        private static int applyAlpha(final int color, final float alpha) {
377d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            final int newAlpha = (int)(Color.alpha(color) * alpha);
378d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            return Color.argb(newAlpha, Color.red(color), Color.green(color), Color.blue(color));
379d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        }
380d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka
381d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        public CharSequence getInvertedText(CharSequence text) {
382d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka            if ((mSuggestionStripOption & AUTO_CORRECT_INVERT) == 0)
383d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka                return null;
384d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            final int len = text.length();
385d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            final Spannable word = new SpannableString(text);
386d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            word.setSpan(mInvertedBackgroundColorSpan, 0, len, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
387d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            word.setSpan(mInvertedForegroundColorSpan, 0, len, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
388d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            return word;
389d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        }
390d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka
39116713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka        public int layout(SuggestedWords suggestions, ViewGroup stripView, ViewGroup paneView,
39216713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                int stripWidth) {
39360a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            if (suggestions.isPunctuationSuggestions()) {
39460a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                return layoutPunctuationSuggestions(suggestions, stripView);
39560a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            }
39660a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka
39760a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            final int countInStrip = mCandidateCountInStrip;
39860a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            setupTexts(suggestions, countInStrip);
399bbf25cf25169f640a361370cde5521ffc7789a1bKen Wakasa            mMoreSuggestionsAvailable = (suggestions.size() > countInStrip);
40060a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            int x = 0;
40160a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            for (int index = 0; index < countInStrip; index++) {
40260a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                final int pos = getWordPosition(index, suggestions);
40360a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka
40460a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                if (index != 0) {
40560a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                    final View divider = mDividers.get(pos);
40660a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                    // Add divider if this isn't the left most suggestion in candidate strip.
40760a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                    stripView.addView(divider);
40860a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                }
40960a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka
41016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                final CharSequence styled = mTexts.get(pos);
41160a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                final TextView word = mWords.get(pos);
412bbf25cf25169f640a361370cde5521ffc7789a1bKen Wakasa                if (index == mCenterCandidateIndex && mMoreSuggestionsAvailable) {
413ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka                    // TODO: This "more suggestions hint" should have nicely designed icon.
414ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka                    word.setCompoundDrawablesWithIntrinsicBounds(
415ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka                            null, null, null, mMoreCandidateHint);
416580e1d7ac0cb90a464a3b3aed88047f85a4ab41fTadashi G. Takaoka                    // HACK: To align with other TextView that has no compound drawables.
417580e1d7ac0cb90a464a3b3aed88047f85a4ab41fTadashi G. Takaoka                    word.setCompoundDrawablePadding(-mMoreCandidateHint.getIntrinsicHeight());
418ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka                } else {
419580e1d7ac0cb90a464a3b3aed88047f85a4ab41fTadashi G. Takaoka                    word.setCompoundDrawablesWithIntrinsicBounds(null, null, null, null);
420ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka                }
421ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka
42260a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                // Disable this candidate if the suggestion is null or empty.
42360a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                word.setEnabled(!TextUtils.isEmpty(styled));
42460a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                word.setTextColor(getCandidateTextColor(index, suggestions, pos));
425ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka                final int width = getCandidateWidth(index, stripWidth);
42660a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                final CharSequence text = getEllipsizedText(styled, width, word.getPaint());
42760a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                final float scaleX = word.getTextScaleX();
42860a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                word.setText(text); // TextView.setText() resets text scale x to 1.0.
42960a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                word.setTextScaleX(scaleX);
43060a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                stripView.addView(word);
431580e1d7ac0cb90a464a3b3aed88047f85a4ab41fTadashi G. Takaoka                setLayoutWeight(word, getCandidateWeight(index), MATCH_PARENT);
43216713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka
43316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                if (DBG) {
43460a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                    final CharSequence debugInfo = getDebugInfo(suggestions, pos);
43516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    if (debugInfo != null) {
43660a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                        final TextView info = mInfos.get(pos);
43716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                        info.setText(debugInfo);
43816713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                        paneView.addView(info);
43916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                        info.measure(WRAP_CONTENT, WRAP_CONTENT);
44060a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                        final int infoWidth = info.getMeasuredWidth();
44116713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                        final int y = info.getMeasuredHeight();
44260a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                        FrameLayoutCompatUtils.placeViewAt(info, x, 0, infoWidth, y);
44360a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                        x += infoWidth * 2;
44416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    }
44560a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                }
44616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka            }
44716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka
44860a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            return countInStrip;
44916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka        }
45016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka
45160a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka        private int getCandidateWidth(int index, int maxWidth) {
45260a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            final int paddings = mPadding * mCandidateCountInStrip;
45360a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            final int dividers = mDividerWidth * (mCandidateCountInStrip - 1);
45460a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            final int availableWidth = maxWidth - paddings - dividers;
45560a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            return (int)(availableWidth * getCandidateWeight(index));
45660a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka        }
45774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
45860a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka        private float getCandidateWeight(int index) {
45960a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            if (index == mCenterCandidateIndex) {
46060a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                return mCenterCandidateWeight;
46160a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            } else {
46260a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                // TODO: Revisit this for cases of 5 or more suggestions
46360a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                return (1.0f - mCenterCandidateWeight) / (mCandidateCountInStrip - 1);
46474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            }
46574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        }
46674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
46760a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka        private void setupTexts(SuggestedWords suggestions, int countInStrip) {
46874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            mTexts.clear();
46960a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            final int count = Math.min(suggestions.size(), countInStrip);
47060a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            for (int pos = 0; pos < count; pos++) {
471d47a955610987c8abdab4d275c044aefc8a7f1dbTadashi G. Takaoka                final CharSequence styled = getStyledCandidateWord(suggestions, pos);
47274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                mTexts.add(styled);
47374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            }
47460a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            for (int pos = count; pos < countInStrip; pos++) {
47560a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                // Make this inactive for touches in layout().
47660a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                mTexts.add(null);
47760a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            }
47874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        }
47974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
48060a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka        private int layoutPunctuationSuggestions(SuggestedWords suggestions, ViewGroup stripView) {
48160a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            final int countInStrip = Math.min(suggestions.size(), PUNCTUATIONS_IN_STRIP);
48260a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            for (int index = 0; index < countInStrip; index++) {
48360a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                if (index != 0) {
48460a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                    // Add divider if this isn't the left most suggestion in candidate strip.
48560a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                    stripView.addView(mDividers.get(index));
48660a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                }
48760a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka
48860a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                final TextView word = mWords.get(index);
48960a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                word.setEnabled(true);
49060a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                word.setTextColor(mColorTypedWord);
49160a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                final CharSequence text = suggestions.getWord(index);
49260a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                word.setText(text);
49360a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                word.setTextScaleX(1.0f);
494ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka                word.setCompoundDrawables(null, null, null, null);
49560a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                stripView.addView(word);
49660a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka                setLayoutWeight(word, 1.0f, mCandidateStripHeight);
49760a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            }
498ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka            mMoreSuggestionsAvailable = false;
49960a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            return countInStrip;
50074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        }
501c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka
502c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka        public void layoutAddToDictionaryHint(CharSequence word, ViewGroup stripView,
503c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka                int stripWidth) {
504c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            final int width = stripWidth - mDividerWidth - mPadding * 2;
505c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka
506c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            final TextView wordView = mWordToSaveView;
507c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            wordView.setTextColor(mColorTypedWord);
508c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            final int wordWidth = (int)(width * mCenterCandidateWeight);
509c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            final CharSequence text = getEllipsizedText(word, wordWidth, wordView.getPaint());
510c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            final float wordScaleX = wordView.getTextScaleX();
511c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            wordView.setTag(word);
512c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            wordView.setText(text);
513c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            wordView.setTextScaleX(wordScaleX);
514c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            stripView.addView(wordView);
515c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            setLayoutWeight(wordView, mCenterCandidateWeight, MATCH_PARENT);
516c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka
517c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            stripView.addView(mDividers.get(0));
518c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka
519c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            final TextView hintView = mHintToSaveView;
520c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            hintView.setTextColor(mColorAutoCorrect);
521c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            final int hintWidth = width - wordWidth;
522c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            final float hintScaleX = getTextScaleX(mHintToSaveText, hintWidth, hintView.getPaint());
523c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            hintView.setText(mHintToSaveText);
524c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            hintView.setTextScaleX(hintScaleX);
525c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            stripView.addView(hintView);
526c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            setLayoutWeight(hintView, 1.0f - mCenterCandidateWeight, MATCH_PARENT);
527c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka        }
52874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka    }
52974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
530923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    /**
531923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     * Construct a CandidateView for showing suggested words for completion.
532923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     * @param context
533923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     * @param attrs
534923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     */
535923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public CandidateView(Context context, AttributeSet attrs) {
53608a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka        this(context, attrs, R.attr.candidateViewStyle);
53708a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka    }
53808a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka
53908a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka    public CandidateView(Context context, AttributeSet attrs, int defStyle) {
540f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka        // Note: Up to version 10 (Gingerbread) of the API, LinearLayout doesn't have 3-argument
541f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka        // constructor.
542f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka        // TODO: Call 3-argument constructor, super(context, attrs, defStyle), when we abandon
543f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka        // backward compatibility with the version 10 or earlier of the API.
544f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka        super(context, attrs);
545f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka        if (defStyle != R.attr.candidateViewStyle) {
546f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka            throw new IllegalArgumentException(
547c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka                    "can't accept defStyle other than R.attr.candidateViewStyle: defStyle="
548f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka                    + defStyle);
549f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka        }
550f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka        setBackgroundDrawable(LinearLayoutCompatUtils.getBackgroundDrawable(
551f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka                context, attrs, defStyle, R.style.CandidateViewStyle));
552923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
55316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka        final LayoutInflater inflater = LayoutInflater.from(context);
55486e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        inflater.inflate(R.layout.candidates_strip, this);
55586e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka
55686e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        mPreviewPopup = new PopupWindow(context);
557e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        mPreviewText = (TextView) inflater.inflate(R.layout.candidate_preview, null);
558580e1d7ac0cb90a464a3b3aed88047f85a4ab41fTadashi G. Takaoka        mPreviewPopup.setWindowLayoutMode(WRAP_CONTENT, WRAP_CONTENT);
559923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mPreviewPopup.setContentView(mPreviewText);
560923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mPreviewPopup.setBackgroundDrawable(null);
561923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
56274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        mCandidatesStrip = (ViewGroup)findViewById(R.id.candidates_strip);
56360a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka        for (int pos = 0; pos < MAX_SUGGESTIONS; pos++) {
56474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            final TextView word = (TextView)inflater.inflate(R.layout.candidate_word, null);
56560a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            word.setTag(pos);
5662442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka            word.setOnClickListener(this);
567ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka            word.setOnLongClickListener(this);
5682442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka            mWords.add(word);
569a1aab83a24e74cb0fad4b1c1e59b18d23ecbdad3Tadashi G. Takaoka            final View divider = inflater.inflate(R.layout.candidate_divider, null);
57060a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            divider.setTag(pos);
571a1aab83a24e74cb0fad4b1c1e59b18d23ecbdad3Tadashi G. Takaoka            divider.setOnClickListener(this);
572a1aab83a24e74cb0fad4b1c1e59b18d23ecbdad3Tadashi G. Takaoka            mDividers.add(divider);
57374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            mInfos.add((TextView)inflater.inflate(R.layout.candidate_info, null));
574c9716b28ce438e06b5cacc07fc002944bcbe24a0Tadashi G. Takaoka        }
575179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaoka
576ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka        mStripParams = new SuggestionsStripParams(context, attrs, defStyle, mWords, mDividers,
577ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka                mInfos);
578ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka        mPaneParams = new SuggestionsPaneParams(mWords, mDividers, mInfos);
579c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka        mStripParams.mWordToSaveView.setOnClickListener(this);
580923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
581c9716b28ce438e06b5cacc07fc002944bcbe24a0Tadashi G. Takaoka
582923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    /**
583c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka     * A connection back to the input method.
584923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     * @param listener
585923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     */
58686e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka    public void setListener(Listener listener, View inputView) {
587c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka        mListener = listener;
58886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        mKeyboardView = inputView.findViewById(R.id.keyboard_view);
589a7eed902f1b0d6871d416412b3c6f91163fa2578Tadashi G. Takaoka        mCandidatesPane = FrameLayoutCompatUtils.getPlacer(
590a7eed902f1b0d6871d416412b3c6f91163fa2578Tadashi G. Takaoka                (ViewGroup)inputView.findViewById(R.id.candidates_pane));
59186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        mCandidatesPane.setOnClickListener(this);
59286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        mCandidatesPaneContainer = (ViewGroup)inputView.findViewById(
59386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka                R.id.candidates_pane_container);
594923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
595923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
5967e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka    public void setSuggestions(SuggestedWords suggestions) {
5979fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if (suggestions == null)
598a15e45ef45931ba46678b39c159518d8aa2d4d65Tadashi G. Takaoka            return;
5999fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        mSuggestions = suggestions;
60055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        if (mShowingAutoCorrectionInverted) {
6019fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            mHandler.postUpdateSuggestions();
60255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        } else {
6039fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            updateSuggestions();
60455b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        }
60555b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka    }
60655b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka
6079fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka    private void updateSuggestions() {
608e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        clear();
60986e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        closeCandidatesPane();
61016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka        if (mSuggestions.size() == 0)
61174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            return;
61274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
61316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka        final int width = getWidth();
61416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka        final int countInStrip = mStripParams.layout(
61516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                mSuggestions, mCandidatesStrip, mCandidatesPane, width);
616bea6b72106853747302fcca11957647982384220Tadashi G. Takaoka        mPaneParams.layout(
61716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                mSuggestions, mCandidatesPane, countInStrip, mStripParams.getTextColor(), width);
61816713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka    }
61974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
62016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka    private static CharSequence getDebugInfo(SuggestedWords suggestions, int pos) {
62160a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka        if (DBG && pos < suggestions.size()) {
62216713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka            final SuggestedWordInfo wordInfo = suggestions.getInfo(pos);
62316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka            if (wordInfo != null) {
62416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                final CharSequence debugInfo = wordInfo.getDebugString();
62516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                if (!TextUtils.isEmpty(debugInfo)) {
62616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    return debugInfo;
627d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka                }
6282442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka            }
62986e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        }
63016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka        return null;
63186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka    }
63286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka
6333118277dd47492089761c0ed1097abaeb376395cTadashi G. Takaoka    private static void setLayoutWeight(View v, float weight, int height) {
63474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        final ViewGroup.LayoutParams lp = v.getLayoutParams();
63574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        if (lp instanceof LinearLayout.LayoutParams) {
63674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            final LinearLayout.LayoutParams llp = (LinearLayout.LayoutParams)lp;
63774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            llp.weight = weight;
63874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            llp.width = 0;
6393118277dd47492089761c0ed1097abaeb376395cTadashi G. Takaoka            llp.height = height;
64074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        }
64174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka    }
64274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
64316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka    private static void centeringCandidates(ViewGroup parent, View from, View to, int width,
64416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka            int parentWidth) {
64516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka        final int fromIndex = parent.indexOfChild(from);
64616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka        final int toIndex = parent.indexOfChild(to);
64716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka        final int offset = (parentWidth - width) / 2;
64886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        for (int index = fromIndex; index <= toIndex; index++) {
64916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka            offsetMargin(parent.getChildAt(index), offset, 0);
65086e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        }
65186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka    }
65286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka
65386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka    private static void offsetMargin(View v, int dx, int dy) {
654862e05a8f0aa03ddc4582d5bf68a3201f348cf1dTadashi G. Takaoka        if (v == null)
655862e05a8f0aa03ddc4582d5bf68a3201f348cf1dTadashi G. Takaoka            return;
6562442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka        final ViewGroup.LayoutParams lp = v.getLayoutParams();
65786e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        if (lp instanceof ViewGroup.MarginLayoutParams) {
6582442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka            final ViewGroup.MarginLayoutParams mlp = (ViewGroup.MarginLayoutParams)lp;
65986e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka            mlp.setMargins(mlp.leftMargin + dx, mlp.topMargin + dy, 0, 0);
66086e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        }
66186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka    }
66286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka
663c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka    private static float getTextScaleX(CharSequence text, int maxWidth, TextPaint paint) {
664c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka        paint.setTextScaleX(1.0f);
665c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka        final int width = getTextWidth(text, paint);
666c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka        if (width <= maxWidth) {
667c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            return 1.0f;
668c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka        }
669c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka        return maxWidth / (float)width;
670c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka    }
671c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka
67274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka    private static CharSequence getEllipsizedText(CharSequence text, int maxWidth,
67374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            TextPaint paint) {
6745cb10f78ed5c0e17798ea5300d8291b613c5e2a9Tadashi G. Takaoka        if (text == null) return null;
67574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        paint.setTextScaleX(1.0f);
67674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        final int width = getTextWidth(text, paint);
67760a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka        if (width <= maxWidth) {
67860a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka            return text;
67960a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka        }
68060a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka        final float scaleX = maxWidth / (float)width;
681b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka        if (scaleX >= MIN_TEXT_XSCALE) {
68274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            paint.setTextScaleX(scaleX);
68374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            return text;
684b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka        }
685b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka
68674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        // Note that TextUtils.ellipsize() use text-x-scale as 1.0 if ellipsize is needed. To get
68760a004f78e73b5208c2a0a79454dabfbc0e1aa33Tadashi G. Takaoka        // squeezed and ellipsized text, passes enlarged width (maxWidth / MIN_TEXT_XSCALE).
68874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        final CharSequence ellipsized = TextUtils.ellipsize(
68974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                text, paint, maxWidth / MIN_TEXT_XSCALE, TextUtils.TruncateAt.MIDDLE);
69074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        paint.setTextScaleX(MIN_TEXT_XSCALE);
69174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        return ellipsized;
692b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka    }
693b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka
69474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka    private static int getTextWidth(CharSequence text, TextPaint paint) {
695b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka        if (TextUtils.isEmpty(text)) return 0;
696fe9b65afa84530d17dd82c770c19de763a50cb58Tadashi G. Takaoka        final Typeface savedTypeface = paint.getTypeface();
69774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        paint.setTypeface(getTextTypeface(text));
698b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka        final int len = text.length();
699b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka        final float[] widths = new float[len];
700b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka        final int count = paint.getTextWidths(text, 0, len, widths);
701fe9b65afa84530d17dd82c770c19de763a50cb58Tadashi G. Takaoka        int width = 0;
702b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka        for (int i = 0; i < count; i++) {
703fe9b65afa84530d17dd82c770c19de763a50cb58Tadashi G. Takaoka            width += Math.round(widths[i] + 0.5f);
704b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka        }
705fe9b65afa84530d17dd82c770c19de763a50cb58Tadashi G. Takaoka        paint.setTypeface(savedTypeface);
706fe9b65afa84530d17dd82c770c19de763a50cb58Tadashi G. Takaoka        return width;
707b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka    }
708b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka
70974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka    private static Typeface getTextTypeface(CharSequence text) {
71074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        if (!(text instanceof SpannableString))
71174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            return Typeface.DEFAULT;
71274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
71374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        final SpannableString ss = (SpannableString)text;
71474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        final StyleSpan[] styles = ss.getSpans(0, text.length(), StyleSpan.class);
71574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        if (styles.length == 0)
71674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            return Typeface.DEFAULT;
71774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
71874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        switch (styles[0].getStyle()) {
71974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        case Typeface.BOLD: return Typeface.DEFAULT_BOLD;
72074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        // TODO: BOLD_ITALIC, ITALIC case?
72174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        default: return Typeface.DEFAULT;
722b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka        }
723b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka    }
724b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka
72586e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka    private void expandCandidatesPane() {
72686e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        mCandidatesPaneContainer.setMinimumHeight(mKeyboardView.getMeasuredHeight());
72774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        mCandidatesPaneContainer.setVisibility(VISIBLE);
72874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        mKeyboardView.setVisibility(GONE);
72986e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka    }
730e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka
73186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka    private void closeCandidatesPane() {
73274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        mCandidatesPaneContainer.setVisibility(GONE);
73374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        mKeyboardView.setVisibility(VISIBLE);
734923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
735923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
736bbf25cf25169f640a361370cde5521ffc7789a1bKen Wakasa    private void toggleCandidatesPane() {
737bbf25cf25169f640a361370cde5521ffc7789a1bKen Wakasa        if (mCandidatesPaneContainer.getVisibility() == VISIBLE) {
738bbf25cf25169f640a361370cde5521ffc7789a1bKen Wakasa            closeCandidatesPane();
739bbf25cf25169f640a361370cde5521ffc7789a1bKen Wakasa        } else {
740bbf25cf25169f640a361370cde5521ffc7789a1bKen Wakasa            expandCandidatesPane();
741bbf25cf25169f640a361370cde5521ffc7789a1bKen Wakasa        }
742bbf25cf25169f640a361370cde5521ffc7789a1bKen Wakasa    }
743bbf25cf25169f640a361370cde5521ffc7789a1bKen Wakasa
74455b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka    public void onAutoCorrectionInverted(CharSequence autoCorrectedWord) {
745d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        final CharSequence inverted = mStripParams.getInvertedText(autoCorrectedWord);
746d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        if (inverted == null)
74755b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            return;
7481e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka        final TextView tv = mWords.get(1);
749d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        tv.setText(inverted);
75055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        mShowingAutoCorrectionInverted = true;
75155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka    }
75255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka
753b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani    public boolean isShowingAddToDictionaryHint() {
754c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka        return mCandidatesStrip.getChildCount() > 0
755c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka                && mCandidatesStrip.getChildAt(0) == mStripParams.mWordToSaveView;
756b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani    }
757b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani
75866a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani    public void showAddToDictionaryHint(CharSequence word) {
759c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka        clear();
760c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka        mStripParams.layoutAddToDictionaryHint(word, mCandidatesStrip, getWidth());
76166a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani    }
76266a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani
7636558253160e2039c87f424bd814f402ecd31de3bKen Wakasa    public boolean dismissAddToDictionaryHint() {
764c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka        if (isShowingAddToDictionaryHint()) {
765c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            clear();
766c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            return true;
767c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka        }
768c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka        return false;
7696558253160e2039c87f424bd814f402ecd31de3bKen Wakasa    }
7706558253160e2039c87f424bd814f402ecd31de3bKen Wakasa
7717e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka    public SuggestedWords getSuggestions() {
772979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        return mSuggestions;
773979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
774979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
775923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void clear() {
77655b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        mShowingAutoCorrectionInverted = false;
77774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        mCandidatesStrip.removeAllViews();
77886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        mCandidatesPane.removeAllViews();
77988110d1799146943c627916ffaa94bbc4dd6f2aeTadashi G. Takaoka        closeCandidatesPane();
780923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
781923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
7826ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani    private void hidePreview() {
783179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaoka        mPreviewPopup.dismiss();
7846ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani    }
785e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka
786c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka    private void showPreview(View view, CharSequence word) {
787e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        if (TextUtils.isEmpty(word))
788e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka            return;
789e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka
790e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        final TextView previewText = mPreviewText;
791d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        previewText.setTextColor(mStripParams.mColorTypedWord);
792e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        previewText.setText(word);
793e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        previewText.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
794e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka                MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
795e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        final int[] offsetInWindow = new int[2];
796c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka        view.getLocationInWindow(offsetInWindow);
797e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        final int posX = offsetInWindow[0];
798e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        final int posY = offsetInWindow[1] - previewText.getMeasuredHeight();
799e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        final PopupWindow previewPopup = mPreviewPopup;
800e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        if (previewPopup.isShowing()) {
801e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka            previewPopup.update(posX, posY, previewPopup.getWidth(), previewPopup.getHeight());
802e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        } else {
803e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka            previewPopup.showAtLocation(this, Gravity.NO_GRAVITY, posX, posY);
804923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
805e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        previewText.setVisibility(VISIBLE);
80655b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        mHandler.postHidePreview();
807923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
808fcba53ef7c874a4685c12c01404c91b779cae1e8Tadashi G. Takaoka
809e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka    private void addToDictionary(CharSequence word) {
810c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka        if (mListener.addWordToDictionary(word.toString())) {
811c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            final CharSequence message = getContext().getString(R.string.added_word, word);
812c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            showPreview(mStripParams.mWordToSaveView, message);
813e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        }
814e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka    }
815e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka
816e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka    @Override
817ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka    public boolean onLongClick(View view) {
818ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka        if (mStripParams.mMoreSuggestionsAvailable) {
819bbf25cf25169f640a361370cde5521ffc7789a1bKen Wakasa            toggleCandidatesPane();
820ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka            return true;
821ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka        }
822ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka        return false;
823ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka    }
824ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka
825ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka    @Override
826e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka    public void onClick(View view) {
827c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka        if (view == mStripParams.mWordToSaveView) {
828c04bbc1ae9be81d25a356407c27a8e7fa22028bfTadashi G. Takaoka            addToDictionary((CharSequence)view.getTag());
829717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka            clear();
830717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka            return;
831717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka        }
832717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka
833ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka        if (view == mCandidatesPane) {
834ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka            closeCandidatesPane();
835ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka            return;
836ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka        }
837ae5c736e37973e26b201d45ff6c139862a6e05cfTadashi G. Takaoka
83886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        final Object tag = view.getTag();
83986e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        if (!(tag instanceof Integer))
84086e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka            return;
84186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        final int index = (Integer) tag;
84237deb112c727dfed5e94d054cf5f00f5d60c8120Tadashi G. Takaoka        if (index >= mSuggestions.size())
84337deb112c727dfed5e94d054cf5f00f5d60c8120Tadashi G. Takaoka            return;
84486e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka
84537deb112c727dfed5e94d054cf5f00f5d60c8120Tadashi G. Takaoka        final CharSequence word = mSuggestions.getWord(index);
846717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka        mListener.pickSuggestionManually(index, word);
84786e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        // Because some punctuation letters are not treated as word separator depending on locale,
84886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        // {@link #setSuggestions} might not be called and candidates pane left opened.
84986e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        closeCandidatesPane();
850923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
85182411d47ba7e8133ed2390c6920945e139a738cesatok
8526ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani    @Override
8536ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani    public void onDetachedFromWindow() {
8546ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani        super.onDetachedFromWindow();
85555b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        mHandler.cancelAllMessages();
8566ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani        hidePreview();
8576ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani    }
858923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project}
859