SuggestionStripView.java revision 16713e5630b93fb5625df26745eb73271f189457
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;
41e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaokaimport android.view.ViewGroup;
42e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaokaimport android.widget.LinearLayout;
43923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.widget.PopupWindow;
44923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.widget.TextView;
45923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
46a7eed902f1b0d6871d416412b3c6f91163fa2578Tadashi G. Takaokaimport com.android.inputmethod.compat.FrameLayoutCompatUtils;
47f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaokaimport com.android.inputmethod.compat.LinearLayoutCompatUtils;
48ddb61ea461b920d87be4ad78c8a36eec1013b965Tadashi G. Takaokaimport com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
49ddb61ea461b920d87be4ad78c8a36eec1013b965Tadashi G. Takaoka
50179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaokaimport java.util.ArrayList;
516f7218627eda110a8454053f8ecb7b80edfdc8cesatokimport java.util.List;
52179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaoka
535ab5807d9163380b56350d5043883c1ea944128cTadashi G. Takaokapublic class CandidateView extends LinearLayout implements OnClickListener {
54923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
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;
6874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka    private final ViewGroup mCandidatesPaneControl;
6974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka    private final TextView mExpandCandidatesPane;
7074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka    private final TextView mCloseCandidatesPane;
7186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka    private ViewGroup mCandidatesPane;
7286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka    private ViewGroup mCandidatesPaneContainer;
7386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka    private View mKeyboardView;
7474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
751e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka    private final ArrayList<TextView> mWords = new ArrayList<TextView>();
762442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka    private final ArrayList<TextView> mInfos = new ArrayList<TextView>();
77ddb61ea461b920d87be4ad78c8a36eec1013b965Tadashi G. Takaoka    private final ArrayList<View> mDividers = new ArrayList<View>();
7874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
7982411d47ba7e8133ed2390c6920945e139a738cesatok    private final PopupWindow mPreviewPopup;
8082411d47ba7e8133ed2390c6920945e139a738cesatok    private final TextView mPreviewText;
8166a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani
82717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka    private final View mTouchToSave;
83717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka    private final TextView mWordToSave;
84717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka
85c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka    private Listener mListener;
867e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka    private SuggestedWords mSuggestions = SuggestedWords.EMPTY;
8755b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka    private boolean mShowingAutoCorrectionInverted;
88e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka    private boolean mShowingAddToDictionary;
896a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani
90d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka    private final SuggestionsStripParams mStripParams;
91d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka    private final SuggestionsPaneParams mPaneParams;
92fe9b65afa84530d17dd82c770c19de763a50cb58Tadashi G. Takaoka    private static final float MIN_TEXT_XSCALE = 0.75f;
93b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka
944f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa    private final UiHandler mHandler = new UiHandler(this);
9555b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka
964f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa    private static class UiHandler extends StaticInnerHandlerWrapper<CandidateView> {
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
10055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        private static final long DELAY_HIDE_PREVIEW = 1000;
10155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        private static final long DELAY_UPDATE_SUGGESTION = 300;
10255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka
1034f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa        public UiHandler(CandidateView outerInstance) {
1044f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa            super(outerInstance);
1054f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa        }
1064f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa
107e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        @Override
108e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        public void dispatchMessage(Message msg) {
1094f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa            final CandidateView candidateView = getOuterInstance();
110e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka            switch (msg.what) {
111e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka            case MSG_HIDE_PREVIEW:
1124f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa                candidateView.hidePreview();
113e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka                break;
11455b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            case MSG_UPDATE_SUGGESTION:
1154f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa                candidateView.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
145d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka    private static class CandidateViewParams {
14674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        public final int mPadding;
14774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        public final int mDividerWidth;
14874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        public final int mDividerHeight;
14974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        public final int mControlWidth;
15016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka        public final int mCandidateStripHeight;
15116713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka
15216713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka        protected final List<TextView> mWords;
15316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka        protected final List<View> mDividers;
15416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka        protected final List<TextView> mInfos;
155d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka
15616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka        protected CandidateViewParams(List<TextView> words, List<View> dividers,
15716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                List<TextView> infos, View control) {
15816713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka            mWords = words;
15916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka            mDividers = dividers;
16016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka            mInfos = infos;
16116713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka
16216713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka            final TextView word = words.get(0);
16316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka            final View divider = dividers.get(0);
164d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            mPadding = word.getCompoundPaddingLeft() + word.getCompoundPaddingRight();
165d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            divider.measure(WRAP_CONTENT, MATCH_PARENT);
166d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            mDividerWidth = divider.getMeasuredWidth();
167d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            mDividerHeight = divider.getMeasuredHeight();
168d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            mControlWidth = control.getMeasuredWidth();
16916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka
17016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka            final Resources res = word.getResources();
17116713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka            mCandidateStripHeight = res.getDimensionPixelOffset(R.dimen.candidate_strip_height);
172d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        }
173d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka    }
174d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka
175d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka    private static class SuggestionsPaneParams extends CandidateViewParams {
17616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka        public SuggestionsPaneParams(List<TextView> words, List<View> dividers,
17716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                List<TextView> infos, View control) {
17816713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka            super(words, dividers, infos, control);
17916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka        }
18016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka
18116713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka        public int layout(SuggestedWords suggestions, ViewGroup paneView, int from, int textColor,
18216713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                int paneWidth) {
18316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka            final int count = Math.min(mWords.size(), suggestions.size());
18416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka            View centeringFrom = null, lastView = null;
18516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka            int x = 0, y = 0;
18616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka            for (int index = from; index < count; index++) {
18716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                final int pos = index;
18816713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                final TextView word = mWords.get(pos);
18916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                final View divider = mDividers.get(pos);
19016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                final TextPaint paint = word.getPaint();
19116713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                word.setTextColor(textColor);
19216713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                final CharSequence styled = suggestions.getWord(pos);
19316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka
19416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                final TextView info;
19516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                if (DBG) {
19616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    final CharSequence debugInfo = getDebugInfo(suggestions, index);
19716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    if (debugInfo != null) {
19816713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                        info = mInfos.get(index);
19916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                        info.setText(debugInfo);
20016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    } else {
20116713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                        info = null;
20216713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    }
20316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                } else {
20416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    info = null;
20516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                }
20616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka
20716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                final CharSequence text;
20816713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                final float scaleX;
20916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                paint.setTextScaleX(1.0f);
21016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                final int textWidth = getTextWidth(styled, paint);
21116713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                int available = paneWidth - x - mPadding;
21216713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                if (textWidth >= available) {
21316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    // Needs new row, centering previous row.
21416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    centeringCandidates(paneView, centeringFrom, lastView, x, paneWidth);
21516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    x = 0;
21616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    y += mCandidateStripHeight;
21716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                }
21816713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                if (x != 0) {
21916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    // Add divider if this isn't the left most suggestion in current row.
22016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    paneView.addView(divider);
22116713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    FrameLayoutCompatUtils.placeViewAt(divider, x, y
22216713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                            + (mCandidateStripHeight - mDividerHeight) / 2, mDividerWidth,
22316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                            mDividerHeight);
22416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    x += mDividerWidth;
22516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                }
22616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                available = paneWidth - x - mPadding;
22716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                text = getEllipsizedText(styled, available, paint);
22816713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                scaleX = paint.getTextScaleX();
22916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                word.setText(text);
23016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                word.setTextScaleX(scaleX);
23116713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                paneView.addView(word);
23216713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                lastView = word;
23316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                if (x == 0)
23416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    centeringFrom = word;
23516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                word.measure(WRAP_CONTENT,
23616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                        MeasureSpec.makeMeasureSpec(mCandidateStripHeight, MeasureSpec.EXACTLY));
23716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                final int width = word.getMeasuredWidth();
23816713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                final int height = word.getMeasuredHeight();
23916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                FrameLayoutCompatUtils.placeViewAt(word, x, y + (mCandidateStripHeight - height)
24016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                        / 2, width, height);
24116713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                x += width;
24216713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                if (info != null) {
24316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    paneView.addView(info);
24416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    lastView = info;
24516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    info.measure(WRAP_CONTENT, WRAP_CONTENT);
24616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    final int infoWidth = info.getMeasuredWidth();
24716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    FrameLayoutCompatUtils.placeViewAt(info, x - infoWidth, y, infoWidth,
24816713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                            info.getMeasuredHeight());
24916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                }
25016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka            }
25116713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka            if (x != 0) {
25216713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                // Centering last candidates row.
25316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                centeringCandidates(paneView, centeringFrom, lastView, x, paneWidth);
25416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka            }
25516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka
25616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka            return count - from;
257d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        }
258d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka    }
259d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka
260d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka    private static class SuggestionsStripParams extends CandidateViewParams {
261d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        private static final int DEFAULT_CANDIDATE_COUNT_IN_STRIP = 3;
262d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        private static final int PUNCTUATIONS_IN_STRIP = 6;
263d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka
264d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        private final int mColorTypedWord;
265d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        private final int mColorAutoCorrect;
266d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        private final int mColorSuggestedCandidate;
267d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        private final int mCandidateCountInStrip;
268d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka
269d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        private static final CharacterStyle BOLD_SPAN = new StyleSpan(Typeface.BOLD);
270d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        private static final CharacterStyle UNDERLINE_SPAN = new UnderlineSpan();
271d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        private final CharacterStyle mInvertedForegroundColorSpan;
272d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        private final CharacterStyle mInvertedBackgroundColorSpan;
273d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        private static final int AUTO_CORRECT_BOLD = 0x01;
274d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        private static final int AUTO_CORRECT_UNDERLINE = 0x02;
275d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        private static final int AUTO_CORRECT_INVERT = 0x04;
276d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka
27716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka        private final TextPaint mPaint;
27874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        private final int mAutoCorrectHighlight;
27974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
280d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        private final ArrayList<CharSequence> mTexts = new ArrayList<CharSequence>();
281d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        private SuggestedWords mSuggestedWords;
28274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
28316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka        private int mCountInStrip;
28474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        // True if the mCountInStrip suggestions can fit in suggestion strip in equally divided
28574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        // width without squeezing the text.
28616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka        private boolean mCanUseFixedWidthColumns;
28716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka        private int mMaxWidth;
28816713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka        private int mAvailableWidthForWords;
28916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka        private int mConstantWidthForPaddings;
29016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka        private int mVariableWidthForWords;
29116713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka        private float mScaleX;
29274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
293d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        public SuggestionsStripParams(Context context, AttributeSet attrs, int defStyle,
29416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                List<TextView> words, List<View> dividers, List<TextView> infos, View control) {
29516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka            super(words, dividers, infos, control);
296d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            final TypedArray a = context.obtainStyledAttributes(
297d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka                    attrs, R.styleable.CandidateView, defStyle, R.style.CandidateViewStyle);
298d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            mAutoCorrectHighlight = a.getInt(R.styleable.CandidateView_autoCorrectHighlight, 0);
299d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            mColorTypedWord = a.getColor(R.styleable.CandidateView_colorTypedWord, 0);
300d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            mColorAutoCorrect = a.getColor(R.styleable.CandidateView_colorAutoCorrect, 0);
301d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            mColorSuggestedCandidate = a.getColor(R.styleable.CandidateView_colorSuggested, 0);
302d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            mCandidateCountInStrip = a.getInt(
303d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka                    R.styleable.CandidateView_candidateCountInStrip,
304d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka                    DEFAULT_CANDIDATE_COUNT_IN_STRIP);
305d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            a.recycle();
306d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka
307d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            mInvertedForegroundColorSpan = new ForegroundColorSpan(mColorTypedWord ^ 0x00ffffff);
308d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            mInvertedBackgroundColorSpan = new BackgroundColorSpan(mColorTypedWord);
309d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka
31074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            mPaint = new TextPaint();
311d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            final float textSize = context.getResources().getDimension(R.dimen.candidate_text_size);
31274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            mPaint.setTextSize(textSize);
31374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        }
31474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
31516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka        public int getTextColor() {
31616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka            return mColorTypedWord;
317d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        }
318d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka
31916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka        private CharSequence getStyledCandidateWord(CharSequence word, boolean isAutoCorrect) {
320d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            if (!isAutoCorrect)
321d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka                return word;
322d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            final int len = word.length();
323d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            final Spannable spannedWord = new SpannableString(word);
324d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            if ((mAutoCorrectHighlight & AUTO_CORRECT_BOLD) != 0)
325d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka                spannedWord.setSpan(BOLD_SPAN, 0, len, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
326d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            if ((mAutoCorrectHighlight & AUTO_CORRECT_UNDERLINE) != 0)
327d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka                spannedWord.setSpan(UNDERLINE_SPAN, 0, len, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
328d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            return spannedWord;
329d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        }
330d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka
33116713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka        private int getWordPosition(int index) {
332d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            if (index >= 2) {
333d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka                return index;
334d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            }
335d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            final boolean willAutoCorrect = !mSuggestedWords.mTypedWordValid
336d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka                    && mSuggestedWords.mHasMinimalSuggestion;
337d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            return willAutoCorrect ? 1 - index : index;
338d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        }
339d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka
34016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka        private int getCandidateTextColor(int pos) {
341d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            final SuggestedWords suggestions = mSuggestedWords;
342d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            final boolean isAutoCorrect = suggestions.mHasMinimalSuggestion
343d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka                    && ((pos == 1 && !suggestions.mTypedWordValid)
344d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka                            || (pos == 0 && suggestions.mTypedWordValid));
345d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            // TODO: Need to revisit this logic with bigram suggestions
346d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            final boolean isSuggestedCandidate = (pos != 0);
347d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            final boolean isPunctuationSuggestions = suggestions.isPunctuationSuggestions();
348d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka
349d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            final int color;
350d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            if (isPunctuationSuggestions) {
351d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka                color = mColorTypedWord;
352d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            } else if (isAutoCorrect) {
353d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka                color = mColorAutoCorrect;
354d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            } else if (isSuggestedCandidate) {
355d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka                color = mColorSuggestedCandidate;
356d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            } else {
357d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka                color = mColorTypedWord;
358d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            }
359d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            final SuggestedWordInfo info = suggestions.getInfo(pos);
360d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            if (info != null && info.isPreviousSuggestedWord()) {
361d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka                return applyAlpha(color, 0.5f);
362d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            } else {
363d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka                return color;
364d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            }
365d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        }
366d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka
367d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        private static int applyAlpha(final int color, final float alpha) {
368d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            final int newAlpha = (int)(Color.alpha(color) * alpha);
369d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            return Color.argb(newAlpha, Color.red(color), Color.green(color), Color.blue(color));
370d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        }
371d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka
372d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        public CharSequence getInvertedText(CharSequence text) {
373d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            if ((mAutoCorrectHighlight & AUTO_CORRECT_INVERT) == 0)
374d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka                return null;
375d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            final int len = text.length();
376d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            final Spannable word = new SpannableString(text);
377d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            word.setSpan(mInvertedBackgroundColorSpan, 0, len, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
378d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            word.setSpan(mInvertedForegroundColorSpan, 0, len, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
379d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            return word;
380d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        }
381d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka
38216713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka        public int layout(SuggestedWords suggestions, ViewGroup stripView, ViewGroup paneView,
38316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                int stripWidth) {
384d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            mSuggestedWords = suggestions;
385d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            final int maxCount = suggestions.isPunctuationSuggestions()
386d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka                    ? PUNCTUATIONS_IN_STRIP : mCandidateCountInStrip;
38774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            final int size = suggestions.size();
388d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka            setupTexts(suggestions, size);
38974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            mCountInStrip = Math.min(maxCount, size);
39074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            mScaleX = 1.0f;
39116713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka            calculateParameters(size, stripWidth);
39216713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka
39316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka            int infoX = 0;
39416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka            for (int index = 0; index < mCountInStrip; index++) {
39516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                final int pos = getWordPosition(index);
39616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                final TextView word = mWords.get(pos);
39716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                final View divider = mDividers.get(pos);
39816713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                final TextPaint paint = word.getPaint();
39916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                // TODO: Reorder candidates in strip as appropriate. The center candidate should
40016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                // hold the word when space is typed (valid typed word or auto corrected word).
40116713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                word.setTextColor(getCandidateTextColor(pos));
40216713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                final CharSequence styled = mTexts.get(pos);
40316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka
40416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                final TextView info;
40516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                if (DBG) {
40616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    final CharSequence debugInfo = getDebugInfo(mSuggestedWords, index);
40716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    if (debugInfo != null) {
40816713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                        info = mInfos.get(index);
40916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                        info.setText(debugInfo);
41016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    } else {
41116713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                        info = null;
41216713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    }
41316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                } else {
41416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    info = null;
41516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                }
41674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
41716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                final CharSequence text;
41816713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                final float scaleX;
41916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    if (index == 0 && mCountInStrip == 1) {
42016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                        text = getEllipsizedText(styled, mMaxWidth, paint);
42116713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                        scaleX = paint.getTextScaleX();
42216713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    } else {
42316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                        text = styled;
42416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                        scaleX = mScaleX;
42516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    }
42616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    word.setText(text);
42716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    word.setTextScaleX(scaleX);
42816713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    if (index != 0) {
42916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                        // Add divider if this isn't the left most suggestion in candidate strip.
43016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                        stripView.addView(divider);
43116713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    }
43216713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    stripView.addView(word);
43316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    if (mCanUseFixedWidthColumns) {
43416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                        setLayoutWeight(word, 1.0f, mCandidateStripHeight);
43516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    } else {
43616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                        final int width = getTextWidth(text, paint) + mPadding;
43716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                        setLayoutWeight(word, width, mCandidateStripHeight);
43816713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    }
43916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    if (info != null) {
44016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                        paneView.addView(info);
44116713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                        info.measure(WRAP_CONTENT, WRAP_CONTENT);
44216713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                        final int width = info.getMeasuredWidth();
44316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                        final int y = info.getMeasuredHeight();
44416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                        FrameLayoutCompatUtils.placeViewAt(info, infoX, 0, width, y);
44516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                        infoX += width * 2;
44616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    }
44716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka            }
44816713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka
44916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka            return mCountInStrip;
45016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka        }
45116713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka
45216713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka        private void calculateParameters(int size, int maxWidth) {
45374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            do {
45474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                mMaxWidth = maxWidth;
45574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                if (size > mCountInStrip) {
45674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                    mMaxWidth -= mControlWidth;
45774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                }
45874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
45974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                tryLayout();
46074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
46174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                if (mCanUseFixedWidthColumns) {
46274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                    return;
46374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                }
46474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                if (mVariableWidthForWords <= mAvailableWidthForWords) {
46574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                    return;
46674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                }
46774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
46874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                final float scaleX = mAvailableWidthForWords / (float)mVariableWidthForWords;
46974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                if (scaleX >= MIN_TEXT_XSCALE) {
47074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                    mScaleX = scaleX;
47174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                    return;
47274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                }
47374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
47474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                mCountInStrip--;
47574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            } while (mCountInStrip > 1);
47674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        }
47774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
47816713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka        private void tryLayout() {
47974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            final int maxCount = mCountInStrip;
48074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            final int dividers = mDividerWidth * (maxCount - 1);
481fe9b65afa84530d17dd82c770c19de763a50cb58Tadashi G. Takaoka            mConstantWidthForPaddings = dividers + mPadding * maxCount;
48274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            mAvailableWidthForWords = mMaxWidth - mConstantWidthForPaddings;
48374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
48474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            mPaint.setTextScaleX(mScaleX);
485fe9b65afa84530d17dd82c770c19de763a50cb58Tadashi G. Takaoka            final int maxFixedWidthForWord = (mMaxWidth - dividers) / maxCount - mPadding;
48674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            mCanUseFixedWidthColumns = true;
48774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            mVariableWidthForWords = 0;
48874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            for (int i = 0; i < maxCount; i++) {
48974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                final int width = getTextWidth(mTexts.get(i), mPaint);
49074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                if (width > maxFixedWidthForWord)
49174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                    mCanUseFixedWidthColumns = false;
49274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                mVariableWidthForWords += width;
49374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            }
49474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        }
49574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
496d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        private void setupTexts(SuggestedWords suggestions, int count) {
49774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            mTexts.clear();
49874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            for (int i = 0; i < count; i++) {
499d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka                final CharSequence word = suggestions.getWord(i);
50074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                final boolean isAutoCorrect = suggestions.mHasMinimalSuggestion
50174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                        && ((i == 1 && !suggestions.mTypedWordValid)
50274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                                || (i == 0 && suggestions.mTypedWordValid));
503d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka                final CharSequence styled = getStyledCandidateWord(word, isAutoCorrect);
50474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                mTexts.add(styled);
50574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            }
50674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        }
50774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
50874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        @Override
50974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        public String toString() {
51074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            return String.format(
51174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                    "count=%d width=%d avail=%d fixcol=%s scaleX=%4.2f const=%d var=%d",
51274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                    mCountInStrip, mMaxWidth, mAvailableWidthForWords, mCanUseFixedWidthColumns,
51374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                    mScaleX, mConstantWidthForPaddings, mVariableWidthForWords);
51474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        }
51574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka    }
51674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
517923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    /**
518923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     * Construct a CandidateView for showing suggested words for completion.
519923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     * @param context
520923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     * @param attrs
521923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     */
522923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public CandidateView(Context context, AttributeSet attrs) {
52308a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka        this(context, attrs, R.attr.candidateViewStyle);
52408a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka    }
52508a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka
52608a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka    public CandidateView(Context context, AttributeSet attrs, int defStyle) {
527f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka        // Note: Up to version 10 (Gingerbread) of the API, LinearLayout doesn't have 3-argument
528f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka        // constructor.
529f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka        // TODO: Call 3-argument constructor, super(context, attrs, defStyle), when we abandon
530f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka        // backward compatibility with the version 10 or earlier of the API.
531f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka        super(context, attrs);
532f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka        if (defStyle != R.attr.candidateViewStyle) {
533f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka            throw new IllegalArgumentException(
534f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka                    "can't accept defStyle other than R.attr.candidayeViewStyle: defStyle="
535f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka                    + defStyle);
536f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka        }
537f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka        setBackgroundDrawable(LinearLayoutCompatUtils.getBackgroundDrawable(
538f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka                context, attrs, defStyle, R.style.CandidateViewStyle));
539923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
54016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka        final LayoutInflater inflater = LayoutInflater.from(context);
54186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        inflater.inflate(R.layout.candidates_strip, this);
54286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka
54386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        mPreviewPopup = new PopupWindow(context);
544e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        mPreviewText = (TextView) inflater.inflate(R.layout.candidate_preview, null);
545e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        mPreviewPopup.setWindowLayoutMode(ViewGroup.LayoutParams.WRAP_CONTENT,
546e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                ViewGroup.LayoutParams.WRAP_CONTENT);
547923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mPreviewPopup.setContentView(mPreviewText);
548923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mPreviewPopup.setBackgroundDrawable(null);
549923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
55074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        mCandidatesStrip = (ViewGroup)findViewById(R.id.candidates_strip);
551e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        for (int i = 0; i < MAX_SUGGESTIONS; i++) {
55274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            final TextView word = (TextView)inflater.inflate(R.layout.candidate_word, null);
5532442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka            word.setTag(i);
5542442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka            word.setOnClickListener(this);
5552442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka            mWords.add(word);
556a1aab83a24e74cb0fad4b1c1e59b18d23ecbdad3Tadashi G. Takaoka            final View divider = inflater.inflate(R.layout.candidate_divider, null);
557a1aab83a24e74cb0fad4b1c1e59b18d23ecbdad3Tadashi G. Takaoka            divider.setTag(i);
558a1aab83a24e74cb0fad4b1c1e59b18d23ecbdad3Tadashi G. Takaoka            divider.setOnClickListener(this);
559a1aab83a24e74cb0fad4b1c1e59b18d23ecbdad3Tadashi G. Takaoka            mDividers.add(divider);
56074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            mInfos.add((TextView)inflater.inflate(R.layout.candidate_info, null));
561c9716b28ce438e06b5cacc07fc002944bcbe24a0Tadashi G. Takaoka        }
562179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaoka
563717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka        mTouchToSave = findViewById(R.id.touch_to_save);
564717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka        mWordToSave = (TextView)findViewById(R.id.word_to_save);
565717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka        mWordToSave.setOnClickListener(this);
566717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka
567e583371b13ebd9aa336d0883e8c174ae4918c758Tadashi G. Takaoka        final TypedArray keyboardViewAttr = context.obtainStyledAttributes(
568e583371b13ebd9aa336d0883e8c174ae4918c758Tadashi G. Takaoka                attrs, R.styleable.KeyboardView, R.attr.keyboardViewStyle, R.style.KeyboardView);
5697c57e3bda1ab1d8c5d5df7acb8aec8c089f9240bTadashi G. Takaoka        final Drawable expandBackground = keyboardViewAttr.getDrawable(
5707c57e3bda1ab1d8c5d5df7acb8aec8c089f9240bTadashi G. Takaoka                R.styleable.KeyboardView_keyBackground);
5717c57e3bda1ab1d8c5d5df7acb8aec8c089f9240bTadashi G. Takaoka        final Drawable closeBackground = keyboardViewAttr.getDrawable(
572e583371b13ebd9aa336d0883e8c174ae4918c758Tadashi G. Takaoka                R.styleable.KeyboardView_keyBackground);
573e583371b13ebd9aa336d0883e8c174ae4918c758Tadashi G. Takaoka        final int keyTextColor = keyboardViewAttr.getColor(
574e583371b13ebd9aa336d0883e8c174ae4918c758Tadashi G. Takaoka                R.styleable.KeyboardView_keyTextColor, 0xFF000000);
575e583371b13ebd9aa336d0883e8c174ae4918c758Tadashi G. Takaoka        keyboardViewAttr.recycle();
576e583371b13ebd9aa336d0883e8c174ae4918c758Tadashi G. Takaoka
57774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        mCandidatesPaneControl = (ViewGroup)findViewById(R.id.candidates_pane_control);
57874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        mExpandCandidatesPane = (TextView)findViewById(R.id.expand_candidates_pane);
5797c57e3bda1ab1d8c5d5df7acb8aec8c089f9240bTadashi G. Takaoka        mExpandCandidatesPane.setBackgroundDrawable(expandBackground);
580e583371b13ebd9aa336d0883e8c174ae4918c758Tadashi G. Takaoka        mExpandCandidatesPane.setTextColor(keyTextColor);
58186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        mExpandCandidatesPane.setOnClickListener(new OnClickListener() {
58286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka            @Override
58386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka            public void onClick(View view) {
58486e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka                expandCandidatesPane();
58586e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka            }
58686e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        });
58774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        mCloseCandidatesPane = (TextView)findViewById(R.id.close_candidates_pane);
5887c57e3bda1ab1d8c5d5df7acb8aec8c089f9240bTadashi G. Takaoka        mCloseCandidatesPane.setBackgroundDrawable(closeBackground);
589e583371b13ebd9aa336d0883e8c174ae4918c758Tadashi G. Takaoka        mCloseCandidatesPane.setTextColor(keyTextColor);
59086e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        mCloseCandidatesPane.setOnClickListener(new OnClickListener() {
59186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka            @Override
59286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka            public void onClick(View view) {
59386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka                closeCandidatesPane();
59486e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka            }
59586e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        });
59674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        mCandidatesPaneControl.measure(WRAP_CONTENT, WRAP_CONTENT);
59708a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka
598d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        mStripParams = new SuggestionsStripParams(context, attrs, defStyle,
59916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                mWords, mDividers, mInfos, mCandidatesPaneControl);
60016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka        mPaneParams = new SuggestionsPaneParams(
60116713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                mWords, mDividers, mInfos, mCandidatesPaneControl);
602923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
603c9716b28ce438e06b5cacc07fc002944bcbe24a0Tadashi G. Takaoka
604923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    /**
605c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka     * A connection back to the input method.
606923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     * @param listener
607923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     */
60886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka    public void setListener(Listener listener, View inputView) {
609c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka        mListener = listener;
61086e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        mKeyboardView = inputView.findViewById(R.id.keyboard_view);
611a7eed902f1b0d6871d416412b3c6f91163fa2578Tadashi G. Takaoka        mCandidatesPane = FrameLayoutCompatUtils.getPlacer(
612a7eed902f1b0d6871d416412b3c6f91163fa2578Tadashi G. Takaoka                (ViewGroup)inputView.findViewById(R.id.candidates_pane));
61386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        mCandidatesPane.setOnClickListener(this);
61486e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        mCandidatesPaneContainer = (ViewGroup)inputView.findViewById(
61586e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka                R.id.candidates_pane_container);
616923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
617923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
6187e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka    public void setSuggestions(SuggestedWords suggestions) {
6199fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if (suggestions == null)
620a15e45ef45931ba46678b39c159518d8aa2d4d65Tadashi G. Takaoka            return;
6219fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        mSuggestions = suggestions;
6224edc7d074b174da447bbf28e62cfb914b236540eTadashi G. Takaoka        mExpandCandidatesPane.setEnabled(false);
62355b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        if (mShowingAutoCorrectionInverted) {
6249fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            mHandler.postUpdateSuggestions();
62555b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        } else {
6269fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            updateSuggestions();
62755b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        }
62855b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka    }
62955b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka
6309fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka    private void updateSuggestions() {
631e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        clear();
63286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        closeCandidatesPane();
63316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka        if (mSuggestions.size() == 0)
63474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            return;
63574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
63616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka        final int width = getWidth();
63716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka        final int countInStrip = mStripParams.layout(
63816713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                mSuggestions, mCandidatesStrip, mCandidatesPane, width);
63916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka        final int countInPane = mPaneParams.layout(
64016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                mSuggestions, mCandidatesPane, countInStrip, mStripParams.getTextColor(), width);
64174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
64216713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka        if (countInPane <= 0 && !DBG) {
64374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            mCandidatesPaneControl.setVisibility(GONE);
64474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        } else {
64574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            mCandidatesPaneControl.setVisibility(VISIBLE);
64674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            mExpandCandidatesPane.setVisibility(VISIBLE);
6474edc7d074b174da447bbf28e62cfb914b236540eTadashi G. Takaoka            mExpandCandidatesPane.setEnabled(true);
64874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        }
64916713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka    }
65074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
65116713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka    private static CharSequence getDebugInfo(SuggestedWords suggestions, int pos) {
65216713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka        if (DBG) {
65316713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka            final SuggestedWordInfo wordInfo = suggestions.getInfo(pos);
65416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka            if (wordInfo != null) {
65516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                final CharSequence debugInfo = wordInfo.getDebugString();
65616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                if (!TextUtils.isEmpty(debugInfo)) {
65716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka                    return debugInfo;
658d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka                }
6592442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka            }
66086e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        }
66116713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka        return null;
66286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka    }
66386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka
6643118277dd47492089761c0ed1097abaeb376395cTadashi G. Takaoka    private static void setLayoutWeight(View v, float weight, int height) {
66574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        final ViewGroup.LayoutParams lp = v.getLayoutParams();
66674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        if (lp instanceof LinearLayout.LayoutParams) {
66774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            final LinearLayout.LayoutParams llp = (LinearLayout.LayoutParams)lp;
66874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            llp.weight = weight;
66974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            llp.width = 0;
6703118277dd47492089761c0ed1097abaeb376395cTadashi G. Takaoka            llp.height = height;
67174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        }
67274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka    }
67374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
67416713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka    private static void centeringCandidates(ViewGroup parent, View from, View to, int width,
67516713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka            int parentWidth) {
67616713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka        final int fromIndex = parent.indexOfChild(from);
67716713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka        final int toIndex = parent.indexOfChild(to);
67816713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka        final int offset = (parentWidth - width) / 2;
67986e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        for (int index = fromIndex; index <= toIndex; index++) {
68016713e5630b93fb5625df26745eb73271f189457Tadashi G. Takaoka            offsetMargin(parent.getChildAt(index), offset, 0);
68186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        }
68286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka    }
68386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka
68486e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka    private static void offsetMargin(View v, int dx, int dy) {
685862e05a8f0aa03ddc4582d5bf68a3201f348cf1dTadashi G. Takaoka        if (v == null)
686862e05a8f0aa03ddc4582d5bf68a3201f348cf1dTadashi G. Takaoka            return;
6872442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka        final ViewGroup.LayoutParams lp = v.getLayoutParams();
68886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        if (lp instanceof ViewGroup.MarginLayoutParams) {
6892442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka            final ViewGroup.MarginLayoutParams mlp = (ViewGroup.MarginLayoutParams)lp;
69086e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka            mlp.setMargins(mlp.leftMargin + dx, mlp.topMargin + dy, 0, 0);
69186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        }
69286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka    }
69386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka
69474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka    private static CharSequence getEllipsizedText(CharSequence text, int maxWidth,
69574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            TextPaint paint) {
69674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        paint.setTextScaleX(1.0f);
69774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        final int width = getTextWidth(text, paint);
69874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        final float scaleX = Math.min(maxWidth / (float)width, 1.0f);
699b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka        if (scaleX >= MIN_TEXT_XSCALE) {
70074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            paint.setTextScaleX(scaleX);
70174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            return text;
702b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka        }
703b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka
70474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        // Note that TextUtils.ellipsize() use text-x-scale as 1.0 if ellipsize is needed. To get
70574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        // squeezed and ellipsezed text, passes enlarged width (maxWidth / MIN_TEXT_XSCALE).
70674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        final CharSequence ellipsized = TextUtils.ellipsize(
70774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                text, paint, maxWidth / MIN_TEXT_XSCALE, TextUtils.TruncateAt.MIDDLE);
70874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        paint.setTextScaleX(MIN_TEXT_XSCALE);
70974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        return ellipsized;
710b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka    }
711b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka
71274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka    private static int getTextWidth(CharSequence text, TextPaint paint) {
713b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka        if (TextUtils.isEmpty(text)) return 0;
714fe9b65afa84530d17dd82c770c19de763a50cb58Tadashi G. Takaoka        final Typeface savedTypeface = paint.getTypeface();
71574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        paint.setTypeface(getTextTypeface(text));
716b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka        final int len = text.length();
717b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka        final float[] widths = new float[len];
718b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka        final int count = paint.getTextWidths(text, 0, len, widths);
719fe9b65afa84530d17dd82c770c19de763a50cb58Tadashi G. Takaoka        int width = 0;
720b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka        for (int i = 0; i < count; i++) {
721fe9b65afa84530d17dd82c770c19de763a50cb58Tadashi G. Takaoka            width += Math.round(widths[i] + 0.5f);
722b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka        }
723fe9b65afa84530d17dd82c770c19de763a50cb58Tadashi G. Takaoka        paint.setTypeface(savedTypeface);
724fe9b65afa84530d17dd82c770c19de763a50cb58Tadashi G. Takaoka        return width;
725b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka    }
726b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka
72774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka    private static Typeface getTextTypeface(CharSequence text) {
72874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        if (!(text instanceof SpannableString))
72974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            return Typeface.DEFAULT;
73074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
73174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        final SpannableString ss = (SpannableString)text;
73274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        final StyleSpan[] styles = ss.getSpans(0, text.length(), StyleSpan.class);
73374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        if (styles.length == 0)
73474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            return Typeface.DEFAULT;
73574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
73674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        switch (styles[0].getStyle()) {
73774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        case Typeface.BOLD: return Typeface.DEFAULT_BOLD;
73874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        // TODO: BOLD_ITALIC, ITALIC case?
73974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        default: return Typeface.DEFAULT;
740b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka        }
741b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka    }
742b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka
74386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka    private void expandCandidatesPane() {
74474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        mExpandCandidatesPane.setVisibility(GONE);
74574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        mCloseCandidatesPane.setVisibility(VISIBLE);
74686e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        mCandidatesPaneContainer.setMinimumHeight(mKeyboardView.getMeasuredHeight());
74774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        mCandidatesPaneContainer.setVisibility(VISIBLE);
74874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        mKeyboardView.setVisibility(GONE);
74986e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka    }
750e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka
75186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka    private void closeCandidatesPane() {
75274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        mExpandCandidatesPane.setVisibility(VISIBLE);
75374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        mCloseCandidatesPane.setVisibility(GONE);
75474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        mCandidatesPaneContainer.setVisibility(GONE);
75574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        mKeyboardView.setVisibility(VISIBLE);
756923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
757923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
75855b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka    public void onAutoCorrectionInverted(CharSequence autoCorrectedWord) {
759d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        final CharSequence inverted = mStripParams.getInvertedText(autoCorrectedWord);
760d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        if (inverted == null)
76155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            return;
7621e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka        final TextView tv = mWords.get(1);
763d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        tv.setText(inverted);
76455b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        mShowingAutoCorrectionInverted = true;
76555b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka    }
76655b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka
767b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani    public boolean isShowingAddToDictionaryHint() {
768b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        return mShowingAddToDictionary;
769b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani    }
770b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani
77166a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani    public void showAddToDictionaryHint(CharSequence word) {
772717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka        mWordToSave.setText(word);
77366a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani        mShowingAddToDictionary = true;
77474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        mCandidatesStrip.setVisibility(GONE);
7755a931efe1e1e8fc0fe046dda1dc3a91e63504114Tadashi G. Takaoka        mCandidatesPaneControl.setVisibility(GONE);
77674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        mTouchToSave.setVisibility(VISIBLE);
77766a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani    }
77866a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani
7796558253160e2039c87f424bd814f402ecd31de3bKen Wakasa    public boolean dismissAddToDictionaryHint() {
7806558253160e2039c87f424bd814f402ecd31de3bKen Wakasa        if (!mShowingAddToDictionary) return false;
7816558253160e2039c87f424bd814f402ecd31de3bKen Wakasa        clear();
7826558253160e2039c87f424bd814f402ecd31de3bKen Wakasa        return true;
7836558253160e2039c87f424bd814f402ecd31de3bKen Wakasa    }
7846558253160e2039c87f424bd814f402ecd31de3bKen Wakasa
7857e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka    public SuggestedWords getSuggestions() {
786979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        return mSuggestions;
787979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
788979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
789923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void clear() {
79066a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani        mShowingAddToDictionary = false;
79155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        mShowingAutoCorrectionInverted = false;
79274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        mTouchToSave.setVisibility(GONE);
7931bd62a56211db2933eb5dd735c108e610111d6fbKen Wakasa        mCandidatesStrip.setVisibility(VISIBLE);
79474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        mCandidatesStrip.removeAllViews();
79586e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        mCandidatesPane.removeAllViews();
79688110d1799146943c627916ffaa94bbc4dd6f2aeTadashi G. Takaoka        closeCandidatesPane();
797923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
798923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
7996ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani    private void hidePreview() {
800179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaoka        mPreviewPopup.dismiss();
8016ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani    }
802e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka
803e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka    private void showPreview(int index, CharSequence word) {
804e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        if (TextUtils.isEmpty(word))
805e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka            return;
806e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka
807e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        final TextView previewText = mPreviewText;
808d95a6365be213c1a1d2ab948fc5b80ee1ce0e3ceTadashi G. Takaoka        previewText.setTextColor(mStripParams.mColorTypedWord);
809e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        previewText.setText(word);
810e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        previewText.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
811e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka                MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
812f20eb55d4f8063f89c6c0abb3af3029fe23cb845Tadashi G. Takaoka        View v = mWords.get(index);
813e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        final int[] offsetInWindow = new int[2];
814e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        v.getLocationInWindow(offsetInWindow);
815e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        final int posX = offsetInWindow[0];
816e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        final int posY = offsetInWindow[1] - previewText.getMeasuredHeight();
817e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        final PopupWindow previewPopup = mPreviewPopup;
818e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        if (previewPopup.isShowing()) {
819e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka            previewPopup.update(posX, posY, previewPopup.getWidth(), previewPopup.getHeight());
820e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        } else {
821e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka            previewPopup.showAtLocation(this, Gravity.NO_GRAVITY, posX, posY);
822923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
823e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        previewText.setVisibility(VISIBLE);
82455b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        mHandler.postHidePreview();
825923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
826fcba53ef7c874a4685c12c01404c91b779cae1e8Tadashi G. Takaoka
827e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka    private void addToDictionary(CharSequence word) {
828c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka        if (mListener.addWordToDictionary(word.toString())) {
829e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka            showPreview(0, getContext().getString(R.string.added_word, word));
830e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        }
831e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka    }
832e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka
833e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka    @Override
834e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka    public void onClick(View view) {
835717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka        if (view == mWordToSave) {
836717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka            addToDictionary(((TextView)view).getText());
837717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka            clear();
838717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka            return;
839717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka        }
840717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka
84186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        final Object tag = view.getTag();
84286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        if (!(tag instanceof Integer))
84386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka            return;
84486e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        final int index = (Integer) tag;
84537deb112c727dfed5e94d054cf5f00f5d60c8120Tadashi G. Takaoka        if (index >= mSuggestions.size())
84637deb112c727dfed5e94d054cf5f00f5d60c8120Tadashi G. Takaoka            return;
84786e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka
84837deb112c727dfed5e94d054cf5f00f5d60c8120Tadashi G. Takaoka        final CharSequence word = mSuggestions.getWord(index);
849717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka        mListener.pickSuggestionManually(index, word);
85086e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        // Because some punctuation letters are not treated as word separator depending on locale,
85186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        // {@link #setSuggestions} might not be called and candidates pane left opened.
85286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        closeCandidatesPane();
853923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
85482411d47ba7e8133ed2390c6920945e139a738cesatok
8556ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani    @Override
8566ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani    public void onDetachedFromWindow() {
8576ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani        super.onDetachedFromWindow();
85855b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        mHandler.cancelAllMessages();
8596ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani        hidePreview();
8606ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani    }
861923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project}
862