SuggestionStripView.java revision 74b6897a12ec603ef835aaa77a01f0c32f49aa1c
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;
24e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaokaimport android.os.Message;
25522d5c16d20657e7d26009fe9c067404e16a6c2aTadashi G. Takaokaimport android.text.Spannable;
26522d5c16d20657e7d26009fe9c067404e16a6c2aTadashi G. Takaokaimport android.text.SpannableString;
27e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaokaimport android.text.Spanned;
28b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaokaimport android.text.TextPaint;
29e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaokaimport android.text.TextUtils;
3055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaokaimport android.text.style.BackgroundColorSpan;
31522d5c16d20657e7d26009fe9c067404e16a6c2aTadashi G. Takaokaimport android.text.style.CharacterStyle;
3255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaokaimport android.text.style.ForegroundColorSpan;
3374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaokaimport android.text.style.StyleSpan;
34522d5c16d20657e7d26009fe9c067404e16a6c2aTadashi G. Takaokaimport android.text.style.UnderlineSpan;
35923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.util.AttributeSet;
36923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.Gravity;
37923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.LayoutInflater;
38923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.View;
39e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaokaimport android.view.View.OnClickListener;
40e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaokaimport android.view.View.OnLongClickListener;
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
53e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaokapublic class CandidateView extends LinearLayout implements OnClickListener, OnLongClickListener {
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
6074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka    private static final CharacterStyle BOLD_SPAN = new StyleSpan(Typeface.BOLD);
6182411d47ba7e8133ed2390c6920945e139a738cesatok    private static final CharacterStyle UNDERLINE_SPAN = new UnderlineSpan();
6286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka    // The maximum number of suggestions available. See {@link Suggest#mPrefMaxSuggestions}.
6386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka    private static final int MAX_SUGGESTIONS = 18;
6474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka    private static final int MATCH_PARENT = ViewGroup.LayoutParams.MATCH_PARENT;
6574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka    private static final int WRAP_CONTENT = ViewGroup.LayoutParams.WRAP_CONTENT;
66923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
678553b5ec315660ab53dd9234e64e1e39ea09ec0fJean Chalard    private static final boolean DBG = LatinImeLogger.sDBG;
686f7218627eda110a8454053f8ecb7b80edfdc8cesatok
6974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka    private final ViewGroup mCandidatesStrip;
7074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka    private final int mCandidateCountInStrip;
7174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka    private static final int DEFAULT_CANDIDATE_COUNT_IN_STRIP = 3;
7274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka    private final ViewGroup mCandidatesPaneControl;
7374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka    private final TextView mExpandCandidatesPane;
7474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka    private final TextView mCloseCandidatesPane;
7586e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka    private ViewGroup mCandidatesPane;
7686e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka    private ViewGroup mCandidatesPaneContainer;
7786e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka    private View mKeyboardView;
7874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
791e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka    private final ArrayList<TextView> mWords = new ArrayList<TextView>();
802442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka    private final ArrayList<TextView> mInfos = new ArrayList<TextView>();
81ddb61ea461b920d87be4ad78c8a36eec1013b965Tadashi G. Takaoka    private final ArrayList<View> mDividers = new ArrayList<View>();
8274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
8386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka    private final int mCandidateStripHeight;
8482411d47ba7e8133ed2390c6920945e139a738cesatok    private final CharacterStyle mInvertedForegroundColorSpan;
8582411d47ba7e8133ed2390c6920945e139a738cesatok    private final CharacterStyle mInvertedBackgroundColorSpan;
8608a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka    private final int mAutoCorrectHighlight;
8708a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka    private static final int AUTO_CORRECT_BOLD = 0x01;
8808a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka    private static final int AUTO_CORRECT_UNDERLINE = 0x02;
8908a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka    private static final int AUTO_CORRECT_INVERT = 0x04;
901e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka    private final int mColorTypedWord;
911e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka    private final int mColorAutoCorrect;
921e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka    private final int mColorSuggestedCandidate;
9374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka    private final int mColorDivider;
9474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
9582411d47ba7e8133ed2390c6920945e139a738cesatok    private final PopupWindow mPreviewPopup;
9682411d47ba7e8133ed2390c6920945e139a738cesatok    private final TextView mPreviewText;
9766a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani
98717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka    private final View mTouchToSave;
99717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka    private final TextView mWordToSave;
100717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka
101c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka    private Listener mListener;
1027e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka    private SuggestedWords mSuggestions = SuggestedWords.EMPTY;
10355b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka    private boolean mShowingAutoCorrectionInverted;
104e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka    private boolean mShowingAddToDictionary;
1056a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani
10674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka    private final CandidateViewLayoutParams mParams;
10774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka    private static final int PUNCTUATIONS_IN_STRIP = 6;
10874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka    private static final float MIN_TEXT_XSCALE = 0.8f;
109b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka
1104f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa    private final UiHandler mHandler = new UiHandler(this);
11155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka
1124f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa    private static class UiHandler extends StaticInnerHandlerWrapper<CandidateView> {
11355b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        private static final int MSG_HIDE_PREVIEW = 0;
11455b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        private static final int MSG_UPDATE_SUGGESTION = 1;
11555b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka
11655b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        private static final long DELAY_HIDE_PREVIEW = 1000;
11755b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        private static final long DELAY_UPDATE_SUGGESTION = 300;
11855b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka
1194f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa        public UiHandler(CandidateView outerInstance) {
1204f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa            super(outerInstance);
1214f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa        }
1224f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa
123e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        @Override
124e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        public void dispatchMessage(Message msg) {
1254f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa            final CandidateView candidateView = getOuterInstance();
126e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka            switch (msg.what) {
127e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka            case MSG_HIDE_PREVIEW:
1284f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa                candidateView.hidePreview();
129e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka                break;
13055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            case MSG_UPDATE_SUGGESTION:
1314f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa                candidateView.updateSuggestions();
13255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka                break;
133e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka            }
134e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        }
13555b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka
13655b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        public void postHidePreview() {
13755b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            cancelHidePreview();
13855b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            sendMessageDelayed(obtainMessage(MSG_HIDE_PREVIEW), DELAY_HIDE_PREVIEW);
13955b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        }
14055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka
14155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        public void cancelHidePreview() {
14255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            removeMessages(MSG_HIDE_PREVIEW);
14355b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        }
14455b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka
1459fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        public void postUpdateSuggestions() {
14655b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            cancelUpdateSuggestions();
1479fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            sendMessageDelayed(obtainMessage(MSG_UPDATE_SUGGESTION),
14855b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka                    DELAY_UPDATE_SUGGESTION);
14955b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        }
15055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka
15155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        public void cancelUpdateSuggestions() {
15255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            removeMessages(MSG_UPDATE_SUGGESTION);
15355b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        }
15455b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka
15555b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        public void cancelAllMessages() {
15655b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            cancelHidePreview();
15755b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            cancelUpdateSuggestions();
15855b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        }
159e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka    }
160179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaoka
16174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka    private static class CandidateViewLayoutParams {
16274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        public final TextPaint mPaint;
16374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        public final int mPadding;
16474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        public final int mDividerWidth;
16574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        public final int mDividerHeight;
16674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        public final int mControlWidth;
16774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        private final int mAutoCorrectHighlight;
16874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
16974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        public final ArrayList<CharSequence> mTexts = new ArrayList<CharSequence>();
17074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
17174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        public int mCountInStrip;
17274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        // True if the mCountInStrip suggestions can fit in suggestion strip in equally divided
17374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        // width without squeezing the text.
17474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        public boolean mCanUseFixedWidthColumns;
17574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        public int mMaxWidth;
17674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        public int mAvailableWidthForWords;
17774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        public int mConstantWidthForPaddings;
17874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        public int mVariableWidthForWords;
17974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        public float mScaleX;
18074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
18174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        public CandidateViewLayoutParams(Resources res, View divider, View control,
18274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                int autoCorrectHighlight) {
18374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            mPaint = new TextPaint();
18474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            final float textSize = res.getDimension(R.dimen.candidate_text_size);
18574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            mPaint.setTextSize(textSize);
18674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            mPadding = res.getDimensionPixelSize(R.dimen.candidate_padding);
18774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            mDividerWidth = divider.getMeasuredWidth();
18874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            mDividerHeight = divider.getMeasuredHeight();
18974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            mControlWidth = control.getMeasuredWidth();
19074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            mAutoCorrectHighlight = autoCorrectHighlight;
19174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        }
19274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
19374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        public void layoutStrip(SuggestedWords suggestions, int maxWidth, int maxCount) {
19474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            final int size = suggestions.size();
19574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            setupTexts(suggestions, size, mAutoCorrectHighlight);
19674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            mCountInStrip = Math.min(maxCount, size);
19774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            mScaleX = 1.0f;
19874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
19974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            do {
20074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                mMaxWidth = maxWidth;
20174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                if (size > mCountInStrip) {
20274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                    mMaxWidth -= mControlWidth;
20374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                }
20474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
20574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                tryLayout();
20674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
20774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                if (mCanUseFixedWidthColumns) {
20874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                    return;
20974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                }
21074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                if (mVariableWidthForWords <= mAvailableWidthForWords) {
21174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                    return;
21274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                }
21374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
21474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                final float scaleX = mAvailableWidthForWords / (float)mVariableWidthForWords;
21574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                if (scaleX >= MIN_TEXT_XSCALE) {
21674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                    mScaleX = scaleX;
21774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                    return;
21874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                }
21974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
22074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                mCountInStrip--;
22174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            } while (mCountInStrip > 1);
22274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        }
22374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
22474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        public void tryLayout() {
22574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            final int maxCount = mCountInStrip;
22674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            final int dividers = mDividerWidth * (maxCount - 1);
22774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            mConstantWidthForPaddings = dividers + mPadding * maxCount * 2;
22874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            mAvailableWidthForWords = mMaxWidth - mConstantWidthForPaddings;
22974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
23074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            mPaint.setTextScaleX(mScaleX);
23174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            final int maxFixedWidthForWord = (mMaxWidth - dividers) / maxCount - mPadding * 2;
23274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            mCanUseFixedWidthColumns = true;
23374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            mVariableWidthForWords = 0;
23474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            for (int i = 0; i < maxCount; i++) {
23574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                final int width = getTextWidth(mTexts.get(i), mPaint);
23674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                if (width > maxFixedWidthForWord)
23774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                    mCanUseFixedWidthColumns = false;
23874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                mVariableWidthForWords += width;
23974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            }
24074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        }
24174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
24274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        private void setupTexts(SuggestedWords suggestions, int count, int autoCorrectHighlight) {
24374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            mTexts.clear();
24474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            for (int i = 0; i < count; i++) {
24574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                final CharSequence suggestion = suggestions.getWord(i);
24674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                if (suggestion == null) continue;
24774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
24874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                final boolean isAutoCorrect = suggestions.mHasMinimalSuggestion
24974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                        && ((i == 1 && !suggestions.mTypedWordValid)
25074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                                || (i == 0 && suggestions.mTypedWordValid));
25174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                // HACK: even if i == 0, we use mColorOther when this suggestion's length is 1
25274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                // and there are multiple suggestions, such as the default punctuation list.
25374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                // TODO: Need to revisit this logic with bigram suggestions
25474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                final CharSequence styled = getStyledCandidateWord(suggestion, isAutoCorrect,
25574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                        autoCorrectHighlight);
25674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                mTexts.add(styled);
25774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            }
25874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        }
25974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
26074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        @Override
26174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        public String toString() {
26274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            return String.format(
26374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                    "count=%d width=%d avail=%d fixcol=%s scaleX=%4.2f const=%d var=%d",
26474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                    mCountInStrip, mMaxWidth, mAvailableWidthForWords, mCanUseFixedWidthColumns,
26574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                    mScaleX, mConstantWidthForPaddings, mVariableWidthForWords);
26674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        }
26774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka    }
26874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
269923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    /**
270923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     * Construct a CandidateView for showing suggested words for completion.
271923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     * @param context
272923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     * @param attrs
273923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     */
274923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public CandidateView(Context context, AttributeSet attrs) {
27508a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka        this(context, attrs, R.attr.candidateViewStyle);
27608a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka    }
27708a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka
27808a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka    public CandidateView(Context context, AttributeSet attrs, int defStyle) {
279f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka        // Note: Up to version 10 (Gingerbread) of the API, LinearLayout doesn't have 3-argument
280f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka        // constructor.
281f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka        // TODO: Call 3-argument constructor, super(context, attrs, defStyle), when we abandon
282f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka        // backward compatibility with the version 10 or earlier of the API.
283f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka        super(context, attrs);
284f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka        if (defStyle != R.attr.candidateViewStyle) {
285f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka            throw new IllegalArgumentException(
286f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka                    "can't accept defStyle other than R.attr.candidayeViewStyle: defStyle="
287f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka                    + defStyle);
288f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka        }
289f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka        setBackgroundDrawable(LinearLayoutCompatUtils.getBackgroundDrawable(
290f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka                context, attrs, defStyle, R.style.CandidateViewStyle));
291923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
29274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        final TypedArray a = context.obtainStyledAttributes(
29374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                attrs, R.styleable.CandidateView, defStyle, R.style.CandidateViewStyle);
29474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        mAutoCorrectHighlight = a.getInt(R.styleable.CandidateView_autoCorrectHighlight, 0);
29574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        mColorTypedWord = a.getColor(R.styleable.CandidateView_colorTypedWord, 0);
29674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        mColorAutoCorrect = a.getColor(R.styleable.CandidateView_colorAutoCorrect, 0);
29774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        mColorSuggestedCandidate = a.getColor(R.styleable.CandidateView_colorSuggested, 0);
29874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        mColorDivider = a.getColor(R.styleable.CandidateView_colorDivider, 0);
29974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        mCandidateCountInStrip = a.getInt(
30074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                R.styleable.CandidateView_candidateCountInStrip, DEFAULT_CANDIDATE_COUNT_IN_STRIP);
30174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        a.recycle();
30274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
30366a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani        Resources res = context.getResources();
304e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        LayoutInflater inflater = LayoutInflater.from(context);
30586e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        inflater.inflate(R.layout.candidates_strip, this);
30686e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka
30786e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        mPreviewPopup = new PopupWindow(context);
308e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        mPreviewText = (TextView) inflater.inflate(R.layout.candidate_preview, null);
309e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        mPreviewPopup.setWindowLayoutMode(ViewGroup.LayoutParams.WRAP_CONTENT,
310e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                ViewGroup.LayoutParams.WRAP_CONTENT);
311923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mPreviewPopup.setContentView(mPreviewText);
312923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mPreviewPopup.setBackgroundDrawable(null);
313923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
31474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        mCandidatesStrip = (ViewGroup)findViewById(R.id.candidates_strip);
31586e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        mCandidateStripHeight = res.getDimensionPixelOffset(R.dimen.candidate_strip_height);
316e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        for (int i = 0; i < MAX_SUGGESTIONS; i++) {
31774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            final TextView word = (TextView)inflater.inflate(R.layout.candidate_word, null);
3182442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka            word.setTag(i);
3192442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka            word.setOnClickListener(this);
320e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka            if (i == 0)
3212442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka                word.setOnLongClickListener(this);
3222442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka            mWords.add(word);
32374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            mInfos.add((TextView)inflater.inflate(R.layout.candidate_info, null));
32474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            mDividers.add(getDivider(inflater));
325c9716b28ce438e06b5cacc07fc002944bcbe24a0Tadashi G. Takaoka        }
326179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaoka
327717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka        mTouchToSave = findViewById(R.id.touch_to_save);
328717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka        mWordToSave = (TextView)findViewById(R.id.word_to_save);
329717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka        mWordToSave.setOnClickListener(this);
330717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka
33108a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka        mInvertedForegroundColorSpan = new ForegroundColorSpan(mColorTypedWord ^ 0x00ffffff);
33208a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka        mInvertedBackgroundColorSpan = new BackgroundColorSpan(mColorTypedWord);
33308a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka
33474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        mCandidatesPaneControl = (ViewGroup)findViewById(R.id.candidates_pane_control);
33574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        mExpandCandidatesPane = (TextView)findViewById(R.id.expand_candidates_pane);
33686e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        mExpandCandidatesPane.setOnClickListener(new OnClickListener() {
33786e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka            @Override
33886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka            public void onClick(View view) {
33986e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka                expandCandidatesPane();
34086e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka            }
34186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        });
34274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        mCloseCandidatesPane = (TextView)findViewById(R.id.close_candidates_pane);
34386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        mCloseCandidatesPane.setOnClickListener(new OnClickListener() {
34486e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka            @Override
34586e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka            public void onClick(View view) {
34686e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka                closeCandidatesPane();
34786e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka            }
34886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        });
34974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        mCandidatesPaneControl.measure(WRAP_CONTENT, WRAP_CONTENT);
35008a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka
35174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        mParams = new CandidateViewLayoutParams(res, mDividers.get(0), mCandidatesPaneControl,
35274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                mAutoCorrectHighlight);
35374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka    }
35474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
35574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka    private View getDivider(LayoutInflater inflater) {
35674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        final TextView divider = (TextView)inflater.inflate(R.layout.candidate_divider, null);
35774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        divider.setTextColor(mColorDivider);
35874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        divider.measure(WRAP_CONTENT, WRAP_CONTENT);
35974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        return divider;
360923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
361c9716b28ce438e06b5cacc07fc002944bcbe24a0Tadashi G. Takaoka
362923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    /**
363c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka     * A connection back to the input method.
364923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     * @param listener
365923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     */
36686e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka    public void setListener(Listener listener, View inputView) {
367c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka        mListener = listener;
36886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        mKeyboardView = inputView.findViewById(R.id.keyboard_view);
369a7eed902f1b0d6871d416412b3c6f91163fa2578Tadashi G. Takaoka        mCandidatesPane = FrameLayoutCompatUtils.getPlacer(
370a7eed902f1b0d6871d416412b3c6f91163fa2578Tadashi G. Takaoka                (ViewGroup)inputView.findViewById(R.id.candidates_pane));
37186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        mCandidatesPane.setOnClickListener(this);
37286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        mCandidatesPaneContainer = (ViewGroup)inputView.findViewById(
37386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka                R.id.candidates_pane_container);
374923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
375923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
3767e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka    public void setSuggestions(SuggestedWords suggestions) {
3779fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if (suggestions == null)
378a15e45ef45931ba46678b39c159518d8aa2d4d65Tadashi G. Takaoka            return;
3799fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        mSuggestions = suggestions;
38055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        if (mShowingAutoCorrectionInverted) {
3819fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            mHandler.postUpdateSuggestions();
38255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        } else {
3839fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            updateSuggestions();
38455b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        }
38555b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka    }
38655b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka
38774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka    private static CharSequence getStyledCandidateWord(CharSequence word, boolean isAutoCorrect,
38874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            int autoCorrectHighlight) {
3891e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka        if (!isAutoCorrect)
3901e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka            return word;
3911e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka        final Spannable spannedWord = new SpannableString(word);
39274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        if ((autoCorrectHighlight & AUTO_CORRECT_BOLD) != 0)
39374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            spannedWord.setSpan(BOLD_SPAN, 0, word.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
39474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        if ((autoCorrectHighlight & AUTO_CORRECT_UNDERLINE) != 0)
39508a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka            spannedWord.setSpan(UNDERLINE_SPAN, 0, word.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
3961e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka        return spannedWord;
3971e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka    }
3981e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka
3991e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka    private int getCandidateTextColor(boolean isAutoCorrect, boolean isSuggestedCandidate,
4001e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka            SuggestedWordInfo info) {
4011e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka        final int color;
40208a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka        if (isAutoCorrect) {
4031e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka            color = mColorAutoCorrect;
40408a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka        } else if (isSuggestedCandidate) {
4051e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka            color = mColorSuggestedCandidate;
4061e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka        } else {
4071e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka            color = mColorTypedWord;
4081e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka        }
4091e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka        if (info != null && info.isPreviousSuggestedWord()) {
4101e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka            final int newAlpha = (int)(Color.alpha(color) * 0.5f);
4111e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka            return Color.argb(newAlpha, Color.red(color), Color.green(color), Color.blue(color));
4121e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka        } else {
4131e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka            return color;
4141e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka        }
4151e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka    }
4161e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka
4179fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka    private void updateSuggestions() {
4189fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        final SuggestedWords suggestions = mSuggestions;
4191e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka        final List<SuggestedWordInfo> suggestedWordInfoList = suggestions.mSuggestedWordInfoList;
42074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        final int paneWidth = getWidth();
42174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        final CandidateViewLayoutParams params = mParams;
4221e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka
423e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        clear();
42486e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        closeCandidatesPane();
42574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        if (suggestions.size() == 0)
42674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            return;
42774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
42874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        params.layoutStrip(suggestions, paneWidth, suggestions.isPunctuationSuggestions()
42974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                ? PUNCTUATIONS_IN_STRIP : mCandidateCountInStrip);
43074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
43174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        final int count = Math.min(mWords.size(), suggestions.size());
43274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        if (count <= params.mCountInStrip) {
43374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            mCandidatesPaneControl.setVisibility(GONE);
43474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        } else {
43574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            mCandidatesPaneControl.setVisibility(VISIBLE);
43674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            mExpandCandidatesPane.setVisibility(VISIBLE);
43774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        }
43874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
43974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        final int countInStrip = params.mCountInStrip;
44074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        int fromIndex = countInStrip;
44174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        int x = 0, y = 0;
442923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        for (int i = 0; i < count; i++) {
44374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            final int pos;
44474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            if (i <= 1) {
44574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                final boolean willAutoCorrect = !suggestions.mTypedWordValid
44674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                        && suggestions.mHasMinimalSuggestion;
44774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                pos = willAutoCorrect ? 1 - i : i;
44874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            } else {
44974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                pos = i;
45074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            }
45174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            final CharSequence suggestion = suggestions.getWord(pos);
4522442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka            if (suggestion == null) continue;
4531e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka
4542442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka            final SuggestedWordInfo suggestionInfo = (suggestedWordInfoList != null)
45574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                    ? suggestedWordInfoList.get(pos) : null;
4561e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka            final boolean isAutoCorrect = suggestions.mHasMinimalSuggestion
45774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                    && ((pos == 1 && !suggestions.mTypedWordValid)
45874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                            || (pos == 0 && suggestions.mTypedWordValid));
4591e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka            // HACK: even if i == 0, we use mColorOther when this suggestion's length is 1
4601e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka            // and there are multiple suggestions, such as the default punctuation list.
4611e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka            // TODO: Need to revisit this logic with bigram suggestions
46274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            final boolean isSuggestedCandidate = (pos != 0);
4632442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka            final boolean isPunctuationSuggestions = (suggestion.length() == 1 && count > 1);
4641e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka
46574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            final TextView word = mWords.get(pos);
46674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            final TextPaint paint = word.getPaint();
46786e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka            // TODO: Reorder candidates in strip as appropriate. The center candidate should hold
46886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka            // the word when space is typed (valid typed word or auto corrected word).
4692442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka            word.setTextColor(getCandidateTextColor(isAutoCorrect,
4702442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka                    isSuggestedCandidate || isPunctuationSuggestions, suggestionInfo));
47174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            final CharSequence styled = params.mTexts.get(pos);
4722442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka
4732442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka            final TextView info;
4742442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka            if (DBG && suggestionInfo != null
4752442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka                    && !TextUtils.isEmpty(suggestionInfo.getDebugString())) {
4762442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka                info = mInfos.get(i);
4772442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka                info.setText(suggestionInfo.getDebugString());
4782442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka            } else {
4792442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka                info = null;
4802442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka            }
4812442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka
48274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            final CharSequence text;
48374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            final float scaleX;
48474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            if (i < countInStrip) {
48574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                if (i == 0 && params.mCountInStrip == 1) {
48674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                    text = getEllipsizedText(styled, params.mMaxWidth, paint);
48774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                    scaleX = paint.getTextScaleX();
48874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                } else {
48974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                    text = styled;
49074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                    scaleX = params.mScaleX;
49174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                }
49274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                word.setText(text);
49374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                word.setTextScaleX(scaleX);
49474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                if (i != 0) {
49574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                    // Add divider if this isn't the left most suggestion in candidate strip.
49674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                    mCandidatesStrip.addView(mDividers.get(i));
49774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                }
49874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                mCandidatesStrip.addView(word);
49974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                if (params.mCanUseFixedWidthColumns) {
50074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                    setLayoutWeight(word, 1.0f);
50174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                } else {
50274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                    final int width = getTextWidth(text, paint) + params.mPadding * 2;
50374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                    setLayoutWeight(word, width);
50474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                }
5052442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka                if (info != null) {
50674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                    word.measure(WRAP_CONTENT, MATCH_PARENT);
507b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka                    final int width = word.getMeasuredWidth();
50874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                    info.measure(WRAP_CONTENT, WRAP_CONTENT);
5092442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka                    final int infoWidth = info.getMeasuredWidth();
5102442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka                    FrameLayoutCompatUtils.placeViewAt(
5117fb04fe007a6d0489168e9c87771db554c873464Tadashi G. Takaoka                            info, width - infoWidth, 0, infoWidth, info.getMeasuredHeight());
5122442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka                }
5132442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka            } else {
51474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                paint.setTextScaleX(1.0f);
51574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                final int textWidth = getTextWidth(styled, paint);
51674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                int available = paneWidth - x - params.mPadding * 2;
51774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                if (textWidth >= available) {
51874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                    // Needs new row, centering previous row.
51986e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka                    centeringCandidates(fromIndex, i - 1, x, paneWidth);
52086e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka                    x = 0;
52186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka                    y += mCandidateStripHeight;
52286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka                    fromIndex = i;
52386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka                }
52486e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka                if (x != 0) {
52574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                    // Add divider if this isn't the left most suggestion in current row.
52674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                    final View divider = mDividers.get(i);
5272442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka                    mCandidatesPane.addView(divider);
5282442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka                    FrameLayoutCompatUtils.placeViewAt(
52974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                            divider, x, y + (mCandidateStripHeight - params.mDividerHeight) / 2,
53074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                            params.mDividerWidth, params.mDividerHeight);
53174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                    x += params.mDividerWidth;
53286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka                }
53374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                available = paneWidth - x - params.mPadding * 2;
53474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                text = getEllipsizedText(styled, available, paint);
53574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                scaleX = paint.getTextScaleX();
53674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                word.setText(text);
53774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                word.setTextScaleX(scaleX);
5382442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka                mCandidatesPane.addView(word);
53974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                word.measure(WRAP_CONTENT, WRAP_CONTENT);
54074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                final int width = word.getMeasuredWidth();
54174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                final int height = word.getMeasuredHeight();
5422442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka                FrameLayoutCompatUtils.placeViewAt(
5432442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka                        word, x, y + (mCandidateStripHeight - height) / 2, width, height);
5442442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka                if (info != null) {
5452442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka                    mCandidatesPane.addView(info);
54674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                    info.measure(WRAP_CONTENT, WRAP_CONTENT);
5472442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka                    final int infoWidth = info.getMeasuredWidth();
5482442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka                    FrameLayoutCompatUtils.placeViewAt(
5492442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka                            info, x + width - infoWidth, y, infoWidth, info.getMeasuredHeight());
5502442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka                }
55186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka                x += width;
5527e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka            }
553923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
55486e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        if (x != 0) {
55586e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka            // Centering last candidates row.
55686e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka            centeringCandidates(fromIndex, count - 1, x, paneWidth);
55786e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        }
55886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka    }
55986e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka
56074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka    private static void setLayoutWeight(View v, float weight) {
56174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        final ViewGroup.LayoutParams lp = v.getLayoutParams();
56274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        if (lp instanceof LinearLayout.LayoutParams) {
56374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            final LinearLayout.LayoutParams llp = (LinearLayout.LayoutParams)lp;
56474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            llp.weight = weight;
56574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            llp.width = 0;
56674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            llp.height = MATCH_PARENT;
56774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        }
56874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka    }
56974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
57086e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka    private void centeringCandidates(int from, int to, int width, int paneWidth) {
57186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        final ViewGroup pane = mCandidatesPane;
57286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        final int fromIndex = pane.indexOfChild(mWords.get(from));
5732442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka        final int toIndex;
5742442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka        if (mInfos.get(to).getParent() != null) {
5752442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka            toIndex = pane.indexOfChild(mInfos.get(to));
5762442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka        } else {
5772442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka            toIndex = pane.indexOfChild(mWords.get(to));
5782442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka        }
57986e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        final int offset = (paneWidth - width) / 2;
58086e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        for (int index = fromIndex; index <= toIndex; index++) {
58186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka            offsetMargin(pane.getChildAt(index), offset, 0);
58286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        }
58386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka    }
58486e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka
58586e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka    private static void offsetMargin(View v, int dx, int dy) {
586862e05a8f0aa03ddc4582d5bf68a3201f348cf1dTadashi G. Takaoka        if (v == null)
587862e05a8f0aa03ddc4582d5bf68a3201f348cf1dTadashi G. Takaoka            return;
5882442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka        final ViewGroup.LayoutParams lp = v.getLayoutParams();
58986e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        if (lp instanceof ViewGroup.MarginLayoutParams) {
5902442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka            final ViewGroup.MarginLayoutParams mlp = (ViewGroup.MarginLayoutParams)lp;
59186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka            mlp.setMargins(mlp.leftMargin + dx, mlp.topMargin + dy, 0, 0);
59286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        }
59386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka    }
59486e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka
59574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka    private static CharSequence getEllipsizedText(CharSequence text, int maxWidth,
59674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            TextPaint paint) {
59774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        paint.setTextScaleX(1.0f);
59874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        final int width = getTextWidth(text, paint);
59974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        final float scaleX = Math.min(maxWidth / (float)width, 1.0f);
600b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka        if (scaleX >= MIN_TEXT_XSCALE) {
60174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            paint.setTextScaleX(scaleX);
60274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            return text;
603b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka        }
604b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka
60574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        // Note that TextUtils.ellipsize() use text-x-scale as 1.0 if ellipsize is needed. To get
60674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        // squeezed and ellipsezed text, passes enlarged width (maxWidth / MIN_TEXT_XSCALE).
60774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        final CharSequence ellipsized = TextUtils.ellipsize(
60874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka                text, paint, maxWidth / MIN_TEXT_XSCALE, TextUtils.TruncateAt.MIDDLE);
60974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        paint.setTextScaleX(MIN_TEXT_XSCALE);
61074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        return ellipsized;
611b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka    }
612b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka
61374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka    private static int getTextWidth(CharSequence text, TextPaint paint) {
614b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka        if (TextUtils.isEmpty(text)) return 0;
61574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        paint.setTypeface(getTextTypeface(text));
616b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka        final int len = text.length();
617b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka        final float[] widths = new float[len];
618b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka        final int count = paint.getTextWidths(text, 0, len, widths);
619b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka        float width = 0;
620b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka        for (int i = 0; i < count; i++) {
621b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka            width += widths[i];
622b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka        }
623b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka        return (int)Math.round(width + 0.5);
624b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka    }
625b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka
62674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka    private static Typeface getTextTypeface(CharSequence text) {
62774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        if (!(text instanceof SpannableString))
62874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            return Typeface.DEFAULT;
62974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
63074b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        final SpannableString ss = (SpannableString)text;
63174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        final StyleSpan[] styles = ss.getSpans(0, text.length(), StyleSpan.class);
63274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        if (styles.length == 0)
63374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka            return Typeface.DEFAULT;
63474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka
63574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        switch (styles[0].getStyle()) {
63674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        case Typeface.BOLD: return Typeface.DEFAULT_BOLD;
63774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        // TODO: BOLD_ITALIC, ITALIC case?
63874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        default: return Typeface.DEFAULT;
639b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka        }
640b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka    }
641b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka
64286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka    private void expandCandidatesPane() {
64374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        mExpandCandidatesPane.setVisibility(GONE);
64474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        mCloseCandidatesPane.setVisibility(VISIBLE);
64586e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        mCandidatesPaneContainer.setMinimumHeight(mKeyboardView.getMeasuredHeight());
64674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        mCandidatesPaneContainer.setVisibility(VISIBLE);
64774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        mKeyboardView.setVisibility(GONE);
64886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka    }
649e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka
65086e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka    private void closeCandidatesPane() {
65174b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        mExpandCandidatesPane.setVisibility(VISIBLE);
65274b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        mCloseCandidatesPane.setVisibility(GONE);
65374b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        mCandidatesPaneContainer.setVisibility(GONE);
65474b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        mKeyboardView.setVisibility(VISIBLE);
655923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
656923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
65755b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka    public void onAutoCorrectionInverted(CharSequence autoCorrectedWord) {
65808a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka        if ((mAutoCorrectHighlight & AUTO_CORRECT_INVERT) == 0)
65955b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            return;
6601e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka        final TextView tv = mWords.get(1);
66155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        final Spannable word = new SpannableString(autoCorrectedWord);
66255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        final int wordLength = word.length();
6638553b5ec315660ab53dd9234e64e1e39ea09ec0fJean Chalard        word.setSpan(mInvertedBackgroundColorSpan, 0, wordLength,
6648553b5ec315660ab53dd9234e64e1e39ea09ec0fJean Chalard                Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
6658553b5ec315660ab53dd9234e64e1e39ea09ec0fJean Chalard        word.setSpan(mInvertedForegroundColorSpan, 0, wordLength,
6668553b5ec315660ab53dd9234e64e1e39ea09ec0fJean Chalard                Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
66755b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        tv.setText(word);
66855b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        mShowingAutoCorrectionInverted = true;
66955b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka    }
67055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka
671b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani    public boolean isShowingAddToDictionaryHint() {
672b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        return mShowingAddToDictionary;
673b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani    }
674b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani
67566a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani    public void showAddToDictionaryHint(CharSequence word) {
676717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka        mWordToSave.setText(word);
67766a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani        mShowingAddToDictionary = true;
67874b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        mCandidatesStrip.setVisibility(GONE);
67974b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        mTouchToSave.setVisibility(VISIBLE);
68066a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani    }
68166a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani
6826558253160e2039c87f424bd814f402ecd31de3bKen Wakasa    public boolean dismissAddToDictionaryHint() {
6836558253160e2039c87f424bd814f402ecd31de3bKen Wakasa        if (!mShowingAddToDictionary) return false;
6846558253160e2039c87f424bd814f402ecd31de3bKen Wakasa        clear();
6856558253160e2039c87f424bd814f402ecd31de3bKen Wakasa        return true;
6866558253160e2039c87f424bd814f402ecd31de3bKen Wakasa    }
6876558253160e2039c87f424bd814f402ecd31de3bKen Wakasa
6887e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka    public SuggestedWords getSuggestions() {
689979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        return mSuggestions;
690979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
691979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
692923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void clear() {
69366a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani        mShowingAddToDictionary = false;
69455b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        mShowingAutoCorrectionInverted = false;
69574b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        mTouchToSave.setVisibility(GONE);
69674b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        mCandidatesStrip.setVisibility(VISIBLE);
69774b6897a12ec603ef835aaa77a01f0c32f49aa1cTadashi G. Takaoka        mCandidatesStrip.removeAllViews();
69886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        mCandidatesPane.removeAllViews();
699923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
700923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
7016ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani    private void hidePreview() {
702179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaoka        mPreviewPopup.dismiss();
7036ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani    }
704e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka
705e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka    private void showPreview(int index, CharSequence word) {
706e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        if (TextUtils.isEmpty(word))
707e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka            return;
708e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka
709e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        final TextView previewText = mPreviewText;
7101e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka        previewText.setTextColor(mColorTypedWord);
711e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        previewText.setText(word);
712e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        previewText.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
713e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka                MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
714f20eb55d4f8063f89c6c0abb3af3029fe23cb845Tadashi G. Takaoka        View v = mWords.get(index);
715e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        final int[] offsetInWindow = new int[2];
716e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        v.getLocationInWindow(offsetInWindow);
717e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        final int posX = offsetInWindow[0];
718e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        final int posY = offsetInWindow[1] - previewText.getMeasuredHeight();
719e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        final PopupWindow previewPopup = mPreviewPopup;
720e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        if (previewPopup.isShowing()) {
721e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka            previewPopup.update(posX, posY, previewPopup.getWidth(), previewPopup.getHeight());
722e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        } else {
723e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka            previewPopup.showAtLocation(this, Gravity.NO_GRAVITY, posX, posY);
724923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
725e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        previewText.setVisibility(VISIBLE);
72655b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        mHandler.postHidePreview();
727923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
728fcba53ef7c874a4685c12c01404c91b779cae1e8Tadashi G. Takaoka
729e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka    private void addToDictionary(CharSequence word) {
730c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka        if (mListener.addWordToDictionary(word.toString())) {
731e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka            showPreview(0, getContext().getString(R.string.added_word, word));
732e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        }
733e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka    }
734e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka
735e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka    @Override
736e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka    public boolean onLongClick(View view) {
73786e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        final Object tag = view.getTag();
73886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        if (!(tag instanceof Integer))
73986e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka            return true;
74086e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        final int index = (Integer) tag;
74137deb112c727dfed5e94d054cf5f00f5d60c8120Tadashi G. Takaoka        if (index >= mSuggestions.size())
74237deb112c727dfed5e94d054cf5f00f5d60c8120Tadashi G. Takaoka            return true;
74386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka
74437deb112c727dfed5e94d054cf5f00f5d60c8120Tadashi G. Takaoka        final CharSequence word = mSuggestions.getWord(index);
745e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        if (word.length() < 2)
746e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka            return false;
747e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        addToDictionary(word);
748e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        return true;
749e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka    }
750e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka
751e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka    @Override
752e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka    public void onClick(View view) {
753717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka        if (view == mWordToSave) {
754717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka            addToDictionary(((TextView)view).getText());
755717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka            clear();
756717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka            return;
757717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka        }
758717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka
75986e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        final Object tag = view.getTag();
76086e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        if (!(tag instanceof Integer))
76186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka            return;
76286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        final int index = (Integer) tag;
76337deb112c727dfed5e94d054cf5f00f5d60c8120Tadashi G. Takaoka        if (index >= mSuggestions.size())
76437deb112c727dfed5e94d054cf5f00f5d60c8120Tadashi G. Takaoka            return;
76586e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka
76637deb112c727dfed5e94d054cf5f00f5d60c8120Tadashi G. Takaoka        final CharSequence word = mSuggestions.getWord(index);
767717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka        mListener.pickSuggestionManually(index, word);
76886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        // Because some punctuation letters are not treated as word separator depending on locale,
76986e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        // {@link #setSuggestions} might not be called and candidates pane left opened.
77086e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        closeCandidatesPane();
771923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
77282411d47ba7e8133ed2390c6920945e139a738cesatok
7736ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani    @Override
7746ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani    public void onDetachedFromWindow() {
7756ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani        super.onDetachedFromWindow();
77655b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        mHandler.cancelAllMessages();
7776ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani        hidePreview();
7786ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani    }
779923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project}
780