SuggestionStripView.java revision b47319867ef3834a222865b8cb6abe62962e70f7
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;
33522d5c16d20657e7d26009fe9c067404e16a6c2aTadashi G. Takaokaimport android.text.style.UnderlineSpan;
34923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.util.AttributeSet;
35923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.Gravity;
36923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.LayoutInflater;
37923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.View;
38e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaokaimport android.view.View.OnClickListener;
39e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaokaimport android.view.View.OnLongClickListener;
40e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaokaimport android.view.ViewGroup;
4108a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaokaimport android.widget.ImageView;
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
6082411d47ba7e8133ed2390c6920945e139a738cesatok    private static final CharacterStyle UNDERLINE_SPAN = new UnderlineSpan();
6186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka    // The maximum number of suggestions available. See {@link Suggest#mPrefMaxSuggestions}.
6286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka    private static final int MAX_SUGGESTIONS = 18;
63b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka    private static final int MATCH_PARENT = MeasureSpec.makeMeasureSpec(
64b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka            -1, MeasureSpec.UNSPECIFIED);
65923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
668553b5ec315660ab53dd9234e64e1e39ea09ec0fJean Chalard    private static final boolean DBG = LatinImeLogger.sDBG;
676f7218627eda110a8454053f8ecb7b80edfdc8cesatok
68717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka    private final View mCandidatesStrip;
6986e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka    private static final int NUM_CANDIDATES_IN_STRIP = 3;
7008a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka    private final ImageView mExpandCandidatesPane;
7108a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka    private final ImageView mCloseCandidatesPane;
7286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka    private ViewGroup mCandidatesPane;
7386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka    private ViewGroup mCandidatesPaneContainer;
7486e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka    private View mKeyboardView;
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>();
7886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka    private final int mCandidateStripHeight;
7982411d47ba7e8133ed2390c6920945e139a738cesatok    private final CharacterStyle mInvertedForegroundColorSpan;
8082411d47ba7e8133ed2390c6920945e139a738cesatok    private final CharacterStyle mInvertedBackgroundColorSpan;
8108a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka    private final int mAutoCorrectHighlight;
8208a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka    private static final int AUTO_CORRECT_BOLD = 0x01;
8308a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka    private static final int AUTO_CORRECT_UNDERLINE = 0x02;
8408a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka    private static final int AUTO_CORRECT_INVERT = 0x04;
851e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka    private final int mColorTypedWord;
861e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka    private final int mColorAutoCorrect;
871e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka    private final int mColorSuggestedCandidate;
8882411d47ba7e8133ed2390c6920945e139a738cesatok    private final PopupWindow mPreviewPopup;
8982411d47ba7e8133ed2390c6920945e139a738cesatok    private final TextView mPreviewText;
9066a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani
91717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka    private final View mTouchToSave;
92717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka    private final TextView mWordToSave;
93717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka
94c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka    private Listener mListener;
957e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka    private SuggestedWords mSuggestions = SuggestedWords.EMPTY;
9655b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka    private boolean mShowingAutoCorrectionInverted;
97e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka    private boolean mShowingAddToDictionary;
986a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani
99b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka    private static final float MIN_TEXT_XSCALE = 0.4f;
100b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka    private static final String ELLIPSIS = "\u2026";
101b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka
1024f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa    private final UiHandler mHandler = new UiHandler(this);
10355b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka
1044f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa    private static class UiHandler extends StaticInnerHandlerWrapper<CandidateView> {
10555b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        private static final int MSG_HIDE_PREVIEW = 0;
10655b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        private static final int MSG_UPDATE_SUGGESTION = 1;
10755b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka
10855b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        private static final long DELAY_HIDE_PREVIEW = 1000;
10955b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        private static final long DELAY_UPDATE_SUGGESTION = 300;
11055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka
1114f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa        public UiHandler(CandidateView outerInstance) {
1124f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa            super(outerInstance);
1134f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa        }
1144f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa
115e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        @Override
116e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        public void dispatchMessage(Message msg) {
1174f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa            final CandidateView candidateView = getOuterInstance();
118e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka            switch (msg.what) {
119e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka            case MSG_HIDE_PREVIEW:
1204f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa                candidateView.hidePreview();
121e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka                break;
12255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            case MSG_UPDATE_SUGGESTION:
1234f0d290c5d112ebac434bd8de4635f7d42ea2df0Ken Wakasa                candidateView.updateSuggestions();
12455b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka                break;
125e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka            }
126e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        }
12755b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka
12855b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        public void postHidePreview() {
12955b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            cancelHidePreview();
13055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            sendMessageDelayed(obtainMessage(MSG_HIDE_PREVIEW), DELAY_HIDE_PREVIEW);
13155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        }
13255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka
13355b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        public void cancelHidePreview() {
13455b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            removeMessages(MSG_HIDE_PREVIEW);
13555b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        }
13655b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka
1379fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        public void postUpdateSuggestions() {
13855b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            cancelUpdateSuggestions();
1399fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            sendMessageDelayed(obtainMessage(MSG_UPDATE_SUGGESTION),
14055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka                    DELAY_UPDATE_SUGGESTION);
14155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        }
14255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka
14355b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        public void cancelUpdateSuggestions() {
14455b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            removeMessages(MSG_UPDATE_SUGGESTION);
14555b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        }
14655b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka
14755b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        public void cancelAllMessages() {
14855b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            cancelHidePreview();
14955b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            cancelUpdateSuggestions();
15055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        }
151e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka    }
152179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaoka
153923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    /**
154923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     * Construct a CandidateView for showing suggested words for completion.
155923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     * @param context
156923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     * @param attrs
157923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     */
158923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public CandidateView(Context context, AttributeSet attrs) {
15908a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka        this(context, attrs, R.attr.candidateViewStyle);
16008a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka    }
16108a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka
16208a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka    public CandidateView(Context context, AttributeSet attrs, int defStyle) {
163f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka        // Note: Up to version 10 (Gingerbread) of the API, LinearLayout doesn't have 3-argument
164f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka        // constructor.
165f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka        // TODO: Call 3-argument constructor, super(context, attrs, defStyle), when we abandon
166f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka        // backward compatibility with the version 10 or earlier of the API.
167f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka        super(context, attrs);
168f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka        if (defStyle != R.attr.candidateViewStyle) {
169f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka            throw new IllegalArgumentException(
170f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka                    "can't accept defStyle other than R.attr.candidayeViewStyle: defStyle="
171f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka                    + defStyle);
172f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka        }
173f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka        setBackgroundDrawable(LinearLayoutCompatUtils.getBackgroundDrawable(
174f921129f9b1083ac9d7d7be8c94701bdf6435b47Tadashi G. Takaoka                context, attrs, defStyle, R.style.CandidateViewStyle));
175923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
17666a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani        Resources res = context.getResources();
177e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        LayoutInflater inflater = LayoutInflater.from(context);
17886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        inflater.inflate(R.layout.candidates_strip, this);
17986e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka
18086e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        mPreviewPopup = new PopupWindow(context);
181e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        mPreviewText = (TextView) inflater.inflate(R.layout.candidate_preview, null);
182e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        mPreviewPopup.setWindowLayoutMode(ViewGroup.LayoutParams.WRAP_CONTENT,
183e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                ViewGroup.LayoutParams.WRAP_CONTENT);
184923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mPreviewPopup.setContentView(mPreviewText);
185923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mPreviewPopup.setBackgroundDrawable(null);
186923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
187717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka        mCandidatesStrip = findViewById(R.id.candidates_strip);
18886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        mCandidateStripHeight = res.getDimensionPixelOffset(R.dimen.candidate_strip_height);
189e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        for (int i = 0; i < MAX_SUGGESTIONS; i++) {
1902442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka            final TextView word, info;
19186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka            switch (i) {
19286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka            case 0:
1932442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka                word = (TextView)findViewById(R.id.word_left);
1942442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka                info = (TextView)findViewById(R.id.info_left);
19586e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka                break;
19686e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka            case 1:
1972442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka                word = (TextView)findViewById(R.id.word_center);
1982442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka                info = (TextView)findViewById(R.id.info_center);
19986e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka                break;
20086e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka            case 2:
2012442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka                word = (TextView)findViewById(R.id.word_right);
2022442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka                info = (TextView)findViewById(R.id.info_right);
20386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka                break;
20486e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka            default:
2052442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka                word = (TextView)inflater.inflate(R.layout.candidate_word, null);
2062442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka                info = (TextView)inflater.inflate(R.layout.candidate_info, null);
20786e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka                break;
20886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka            }
2092442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka            word.setTag(i);
2102442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka            word.setOnClickListener(this);
211e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka            if (i == 0)
2122442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka                word.setOnLongClickListener(this);
2132442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka            mWords.add(word);
2142442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka            mInfos.add(info);
215ddb61ea461b920d87be4ad78c8a36eec1013b965Tadashi G. Takaoka            if (i > 0) {
216070760dc5abdb9a850a94c509eeb9f486515af59Tadashi G. Takaoka                final View divider = inflater.inflate(R.layout.candidate_divider, null);
217b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka                divider.measure(MATCH_PARENT, MATCH_PARENT);
218ddb61ea461b920d87be4ad78c8a36eec1013b965Tadashi G. Takaoka                mDividers.add(divider);
219ddb61ea461b920d87be4ad78c8a36eec1013b965Tadashi G. Takaoka            }
220c9716b28ce438e06b5cacc07fc002944bcbe24a0Tadashi G. Takaoka        }
221179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaoka
222717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka        mTouchToSave = findViewById(R.id.touch_to_save);
223717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka        mWordToSave = (TextView)findViewById(R.id.word_to_save);
224717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka        mWordToSave.setOnClickListener(this);
225717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka
22608a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka        final TypedArray a = context.obtainStyledAttributes(
22708a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka                attrs, R.styleable.CandidateView, defStyle, R.style.CandidateViewStyle);
22808a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka        mAutoCorrectHighlight = a.getInt(R.styleable.CandidateView_autoCorrectHighlight, 0);
22908a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka        mColorTypedWord = a.getColor(R.styleable.CandidateView_colorTypedWord, 0);
23008a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka        mColorAutoCorrect = a.getColor(R.styleable.CandidateView_colorAutoCorrect, 0);
23108a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka        mColorSuggestedCandidate = a.getColor(R.styleable.CandidateView_colorSuggested, 0);
23208a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka        mInvertedForegroundColorSpan = new ForegroundColorSpan(mColorTypedWord ^ 0x00ffffff);
23308a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka        mInvertedBackgroundColorSpan = new BackgroundColorSpan(mColorTypedWord);
23408a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka
23508a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka        mExpandCandidatesPane = (ImageView)findViewById(R.id.expand_candidates_pane);
23608a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka        mExpandCandidatesPane.setImageDrawable(
23708a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka                a.getDrawable(R.styleable.CandidateView_iconExpandPane));
23886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        mExpandCandidatesPane.setOnClickListener(new OnClickListener() {
23986e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka            @Override
24086e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka            public void onClick(View view) {
24186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka                expandCandidatesPane();
24286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka            }
24386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        });
24408a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka        mCloseCandidatesPane = (ImageView)findViewById(R.id.close_candidates_pane);
24508a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka        mCloseCandidatesPane.setImageDrawable(
24608a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka                a.getDrawable(R.styleable.CandidateView_iconClosePane));
24786e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        mCloseCandidatesPane.setOnClickListener(new OnClickListener() {
24886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka            @Override
24986e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka            public void onClick(View view) {
25086e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka                closeCandidatesPane();
25186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka            }
25286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        });
25308a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka
25408a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka        a.recycle();
255923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
256c9716b28ce438e06b5cacc07fc002944bcbe24a0Tadashi G. Takaoka
257923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    /**
258c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka     * A connection back to the input method.
259923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     * @param listener
260923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     */
26186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka    public void setListener(Listener listener, View inputView) {
262c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka        mListener = listener;
26386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        mKeyboardView = inputView.findViewById(R.id.keyboard_view);
264a7eed902f1b0d6871d416412b3c6f91163fa2578Tadashi G. Takaoka        mCandidatesPane = FrameLayoutCompatUtils.getPlacer(
265a7eed902f1b0d6871d416412b3c6f91163fa2578Tadashi G. Takaoka                (ViewGroup)inputView.findViewById(R.id.candidates_pane));
26686e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        mCandidatesPane.setOnClickListener(this);
26786e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        mCandidatesPaneContainer = (ViewGroup)inputView.findViewById(
26886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka                R.id.candidates_pane_container);
269923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
270923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
2717e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka    public void setSuggestions(SuggestedWords suggestions) {
2729fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        if (suggestions == null)
273a15e45ef45931ba46678b39c159518d8aa2d4d65Tadashi G. Takaoka            return;
2749fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        mSuggestions = suggestions;
27555b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        if (mShowingAutoCorrectionInverted) {
2769fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            mHandler.postUpdateSuggestions();
27755b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        } else {
2789fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka            updateSuggestions();
27955b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        }
28055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka    }
28155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka
282b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka    private CharSequence getStyledCandidateWord(CharSequence word, TextView v,
283b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka            boolean isAutoCorrect) {
284b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka        v.setTypeface(Typeface.DEFAULT);
2851e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka        if (!isAutoCorrect)
2861e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka            return word;
2871e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka        final Spannable spannedWord = new SpannableString(word);
28808a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka        if ((mAutoCorrectHighlight & AUTO_CORRECT_BOLD) != 0)
289b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka            v.setTypeface(Typeface.DEFAULT_BOLD);
29008a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka        if ((mAutoCorrectHighlight & AUTO_CORRECT_UNDERLINE) != 0)
29108a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka            spannedWord.setSpan(UNDERLINE_SPAN, 0, word.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
2921e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka        return spannedWord;
2931e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka    }
2941e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka
2951e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka    private int getCandidateTextColor(boolean isAutoCorrect, boolean isSuggestedCandidate,
2961e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka            SuggestedWordInfo info) {
2971e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka        final int color;
29808a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka        if (isAutoCorrect) {
2991e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka            color = mColorAutoCorrect;
30008a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka        } else if (isSuggestedCandidate) {
3011e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka            color = mColorSuggestedCandidate;
3021e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka        } else {
3031e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka            color = mColorTypedWord;
3041e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka        }
3051e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka        if (info != null && info.isPreviousSuggestedWord()) {
3061e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka            final int newAlpha = (int)(Color.alpha(color) * 0.5f);
3071e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka            return Color.argb(newAlpha, Color.red(color), Color.green(color), Color.blue(color));
3081e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka        } else {
3091e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka            return color;
3101e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka        }
3111e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka    }
3121e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka
3139fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka    private void updateSuggestions() {
3149fb8c6dd48dfa4e45827628a866d9b13c4c6c799Tadashi G. Takaoka        final SuggestedWords suggestions = mSuggestions;
3151e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka        final List<SuggestedWordInfo> suggestedWordInfoList = suggestions.mSuggestedWordInfoList;
3161e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka
317e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        clear();
31886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        final int paneWidth = getWidth();
31986e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        final int dividerWidth = mDividers.get(0).getMeasuredWidth();
3202442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka        final int dividerHeight = mDividers.get(0).getMeasuredHeight();
32186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        int x = 0;
32286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        int y = 0;
32386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        int fromIndex = NUM_CANDIDATES_IN_STRIP;
324ec5ae3a1b6ce6d6c87406def849995ec63816c55Ken Wakasa        final int count = Math.min(mWords.size(), suggestions.size());
32586e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        closeCandidatesPane();
326b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka        mExpandCandidatesPane.setVisibility(count > NUM_CANDIDATES_IN_STRIP ? VISIBLE : GONE);
327923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        for (int i = 0; i < count; i++) {
3282442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka            final CharSequence suggestion = suggestions.getWord(i);
3292442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka            if (suggestion == null) continue;
3301e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka
3312442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka            final SuggestedWordInfo suggestionInfo = (suggestedWordInfoList != null)
3321e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka                    ? suggestedWordInfoList.get(i) : null;
3331e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka            final boolean isAutoCorrect = suggestions.mHasMinimalSuggestion
33482411d47ba7e8133ed2390c6920945e139a738cesatok                    && ((i == 1 && !suggestions.mTypedWordValid)
3351e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka                            || (i == 0 && suggestions.mTypedWordValid));
3361e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka            // HACK: even if i == 0, we use mColorOther when this suggestion's length is 1
3371e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka            // and there are multiple suggestions, such as the default punctuation list.
3381e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka            // TODO: Need to revisit this logic with bigram suggestions
3391e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka            final boolean isSuggestedCandidate = (i != 0);
3402442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka            final boolean isPunctuationSuggestions = (suggestion.length() == 1 && count > 1);
3411e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka
3422442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka            final TextView word = mWords.get(i);
34386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka            // TODO: Reorder candidates in strip as appropriate. The center candidate should hold
34486e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka            // the word when space is typed (valid typed word or auto corrected word).
3452442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka            word.setTextColor(getCandidateTextColor(isAutoCorrect,
3462442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka                    isSuggestedCandidate || isPunctuationSuggestions, suggestionInfo));
347b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka            final CharSequence text = getStyledCandidateWord(suggestion, word, isAutoCorrect);
348b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka            if (i < NUM_CANDIDATES_IN_STRIP) {
349b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka                final View parent = (View)word.getParent();
350b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka                final int width = parent.getWidth() - word.getPaddingLeft()
351b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka                        - word.getPaddingRight();
352b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka                setTextWithAutoScaleAndEllipsis(text, width, word);
353b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka            } else {
354b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka                setTextWithAutoScaleAndEllipsis(text, paneWidth, word);
355b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka            }
3562442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka
3572442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka            final TextView info;
3582442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka            if (DBG && suggestionInfo != null
3592442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka                    && !TextUtils.isEmpty(suggestionInfo.getDebugString())) {
3602442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka                info = mInfos.get(i);
3612442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka                info.setText(suggestionInfo.getDebugString());
3622442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka                info.setVisibility(View.VISIBLE);
3632442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka            } else {
3642442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka                info = null;
3652442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka            }
3662442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka
3672442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka            if (i < NUM_CANDIDATES_IN_STRIP) {
3682442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka                if (info != null) {
369b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka                    word.measure(MATCH_PARENT, MATCH_PARENT);
370b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka                    info.measure(MATCH_PARENT, MATCH_PARENT);
371b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka                    final int width = word.getMeasuredWidth();
3722442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka                    final int infoWidth = info.getMeasuredWidth();
3732442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka                    FrameLayoutCompatUtils.placeViewAt(
3747fb04fe007a6d0489168e9c87771db554c873464Tadashi G. Takaoka                            info, width - infoWidth, 0, infoWidth, info.getMeasuredHeight());
3752442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka                }
3762442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka            } else {
377b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka                word.measure(MATCH_PARENT, MATCH_PARENT);
378b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka                final int width = word.getMeasuredWidth();
379b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka                final int height = word.getMeasuredHeight();
38086e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka                // TODO: Handle overflow case.
38186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka                if (dividerWidth + x + width >= paneWidth) {
38286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka                    centeringCandidates(fromIndex, i - 1, x, paneWidth);
38386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka                    x = 0;
38486e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka                    y += mCandidateStripHeight;
38586e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka                    fromIndex = i;
38686e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka                }
38786e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka                if (x != 0) {
38886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka                    final View divider = mDividers.get(i - NUM_CANDIDATES_IN_STRIP);
3892442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka                    mCandidatesPane.addView(divider);
3902442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka                    FrameLayoutCompatUtils.placeViewAt(
3912442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka                            divider, x, y + (mCandidateStripHeight - dividerHeight) / 2,
3922442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka                            dividerWidth, dividerHeight);
39386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka                    x += dividerWidth;
39486e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka                }
3952442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka                mCandidatesPane.addView(word);
3962442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka                FrameLayoutCompatUtils.placeViewAt(
3972442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka                        word, x, y + (mCandidateStripHeight - height) / 2, width, height);
3982442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka                if (info != null) {
3992442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka                    mCandidatesPane.addView(info);
400b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka                    info.measure(MATCH_PARENT, MATCH_PARENT);
4012442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka                    final int infoWidth = info.getMeasuredWidth();
4022442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka                    FrameLayoutCompatUtils.placeViewAt(
4032442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka                            info, x + width - infoWidth, y, infoWidth, info.getMeasuredHeight());
4042442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka                }
40586e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka                x += width;
4067e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka            }
407923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
40886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        if (x != 0) {
40986e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka            // Centering last candidates row.
41086e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka            centeringCandidates(fromIndex, count - 1, x, paneWidth);
41186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        }
41286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka    }
41386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka
41486e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka    private void centeringCandidates(int from, int to, int width, int paneWidth) {
41586e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        final ViewGroup pane = mCandidatesPane;
41686e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        final int fromIndex = pane.indexOfChild(mWords.get(from));
4172442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka        final int toIndex;
4182442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka        if (mInfos.get(to).getParent() != null) {
4192442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka            toIndex = pane.indexOfChild(mInfos.get(to));
4202442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka        } else {
4212442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka            toIndex = pane.indexOfChild(mWords.get(to));
4222442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka        }
42386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        final int offset = (paneWidth - width) / 2;
42486e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        for (int index = fromIndex; index <= toIndex; index++) {
42586e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka            offsetMargin(pane.getChildAt(index), offset, 0);
42686e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        }
42786e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka    }
42886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka
42986e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka    private static void offsetMargin(View v, int dx, int dy) {
430862e05a8f0aa03ddc4582d5bf68a3201f348cf1dTadashi G. Takaoka        if (v == null)
431862e05a8f0aa03ddc4582d5bf68a3201f348cf1dTadashi G. Takaoka            return;
4322442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka        final ViewGroup.LayoutParams lp = v.getLayoutParams();
43386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        if (lp instanceof ViewGroup.MarginLayoutParams) {
4342442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka            final ViewGroup.MarginLayoutParams mlp = (ViewGroup.MarginLayoutParams)lp;
43586e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka            mlp.setMargins(mlp.leftMargin + dx, mlp.topMargin + dy, 0, 0);
43686e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        }
43786e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka    }
43886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka
439b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka    private static void setTextWithAutoScaleAndEllipsis(CharSequence text, int w, TextView v) {
440b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka        // To prevent partially rendered character at the end of text, subtract few extra pixels
441b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka        // from the width.
442b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka        final int width = w - 4;
443b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka
444b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka        final TextPaint paint = v.getPaint();
445b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka        final int textWidth = getTextWidth(text, paint, 1.0f);
446b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka        if (textWidth < width || textWidth == 0 || width <= 0) {
447b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka            v.setTextScaleX(1.0f);
448b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka            v.setText(text);
449b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka            return;
450b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka        }
451b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka
452b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka        final float scaleX = Math.min((float)width / textWidth, 1.0f);
453b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka        if (scaleX >= MIN_TEXT_XSCALE) {
454b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka            v.setTextScaleX(scaleX);
455b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka            v.setText(text);
456b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka            return;
457b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka        }
458b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka
459b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka        final int truncatedWidth = width - getTextWidth(ELLIPSIS, paint, MIN_TEXT_XSCALE);
460b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka        final CharSequence ellipsized = getTextEllipsizedAtStart(text, paint, truncatedWidth);
461b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka        v.setTextScaleX(MIN_TEXT_XSCALE);
462b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka        v.setText(ELLIPSIS);
463b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka        v.append(ellipsized);
464b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka    }
465b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka
466b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka    private static int getTextWidth(CharSequence text, TextPaint paint, float scaleX) {
467b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka        if (TextUtils.isEmpty(text)) return 0;
468b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka        final int len = text.length();
469b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka        final float[] widths = new float[len];
470b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka        paint.setTextScaleX(scaleX);
471b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka        final int count = paint.getTextWidths(text, 0, len, widths);
472b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka        float width = 0;
473b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka        for (int i = 0; i < count; i++) {
474b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka            width += widths[i];
475b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka        }
476b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka        return (int)Math.round(width + 0.5);
477b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka    }
478b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka
479b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka    private static CharSequence getTextEllipsizedAtStart(CharSequence text, TextPaint paint,
480b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka            int maxWidth) {
481b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka        final int len = text.length();
482b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka        final float[] widths = new float[len];
483b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka        final int count = paint.getTextWidths(text, 0, len, widths);
484b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka        float width = 0;
485b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka        for (int i = count - 1; i >= 0; i--) {
486b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka            width += widths[i];
487b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka            if (width > maxWidth)
488b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka                return text.subSequence(i + 1, len);
489b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka        }
490b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka        return text;
491b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka    }
492b47319867ef3834a222865b8cb6abe62962e70f7Tadashi G. Takaoka
49386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka    private void expandCandidatesPane() {
49486e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        mExpandCandidatesPane.setVisibility(View.GONE);
49586e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        mCloseCandidatesPane.setVisibility(View.VISIBLE);
49686e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        mCandidatesPaneContainer.setMinimumHeight(mKeyboardView.getMeasuredHeight());
49786e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        mCandidatesPaneContainer.setVisibility(View.VISIBLE);
49886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        mKeyboardView.setVisibility(View.GONE);
49986e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka    }
500e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka
50186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka    private void closeCandidatesPane() {
50286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        mExpandCandidatesPane.setVisibility(View.VISIBLE);
50386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        mCloseCandidatesPane.setVisibility(View.GONE);
50486e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        mCandidatesPaneContainer.setVisibility(View.GONE);
50586e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        mKeyboardView.setVisibility(View.VISIBLE);
506923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
507923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
50855b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka    public void onAutoCorrectionInverted(CharSequence autoCorrectedWord) {
50908a6f2aea71d998206c47c16dcda4eaa90f8c9eaTadashi G. Takaoka        if ((mAutoCorrectHighlight & AUTO_CORRECT_INVERT) == 0)
51055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka            return;
5111e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka        final TextView tv = mWords.get(1);
51255b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        final Spannable word = new SpannableString(autoCorrectedWord);
51355b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        final int wordLength = word.length();
5148553b5ec315660ab53dd9234e64e1e39ea09ec0fJean Chalard        word.setSpan(mInvertedBackgroundColorSpan, 0, wordLength,
5158553b5ec315660ab53dd9234e64e1e39ea09ec0fJean Chalard                Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
5168553b5ec315660ab53dd9234e64e1e39ea09ec0fJean Chalard        word.setSpan(mInvertedForegroundColorSpan, 0, wordLength,
5178553b5ec315660ab53dd9234e64e1e39ea09ec0fJean Chalard                Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
51855b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        tv.setText(word);
51955b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        mShowingAutoCorrectionInverted = true;
52055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka    }
52155b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka
522b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani    public boolean isShowingAddToDictionaryHint() {
523b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani        return mShowingAddToDictionary;
524b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani    }
525b00a1d0c0adbdfc507676772201e979e539a2801Amith Yamasani
52666a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani    public void showAddToDictionaryHint(CharSequence word) {
527717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka        mWordToSave.setText(word);
52866a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani        mShowingAddToDictionary = true;
529717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka        mCandidatesStrip.setVisibility(View.GONE);
530717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka        mTouchToSave.setVisibility(View.VISIBLE);
53166a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani    }
53266a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani
5336558253160e2039c87f424bd814f402ecd31de3bKen Wakasa    public boolean dismissAddToDictionaryHint() {
5346558253160e2039c87f424bd814f402ecd31de3bKen Wakasa        if (!mShowingAddToDictionary) return false;
5356558253160e2039c87f424bd814f402ecd31de3bKen Wakasa        clear();
5366558253160e2039c87f424bd814f402ecd31de3bKen Wakasa        return true;
5376558253160e2039c87f424bd814f402ecd31de3bKen Wakasa    }
5386558253160e2039c87f424bd814f402ecd31de3bKen Wakasa
5397e181fe1010c8eac7814cc67a0c4b3864a10b151Tadashi G. Takaoka    public SuggestedWords getSuggestions() {
540979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        return mSuggestions;
541979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
542979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
543923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void clear() {
54466a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani        mShowingAddToDictionary = false;
54555b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        mShowingAutoCorrectionInverted = false;
5462442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka        for (int i = 0; i < NUM_CANDIDATES_IN_STRIP; i++) {
54786e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka            mWords.get(i).setText(null);
5482442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka            mInfos.get(i).setVisibility(View.GONE);
5492442e779857e7eda253aadcb1c4dff5ccb3e53f4Tadashi G. Takaoka        }
550717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka        mTouchToSave.setVisibility(View.GONE);
551717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka        mCandidatesStrip.setVisibility(View.VISIBLE);
55286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        mCandidatesPane.removeAllViews();
553923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
554923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
5556ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani    private void hidePreview() {
556179ada958b0bb46c6b9c8eb8b220d84dd3db855aTadashi G. Takaoka        mPreviewPopup.dismiss();
5576ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani    }
558e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka
559e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka    private void showPreview(int index, CharSequence word) {
560e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        if (TextUtils.isEmpty(word))
561e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka            return;
562e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka
563e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        final TextView previewText = mPreviewText;
5641e273fa6d1e8babfebebbbe331d87d3854755e7fTadashi G. Takaoka        previewText.setTextColor(mColorTypedWord);
565e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        previewText.setText(word);
566e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        previewText.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
567e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka                MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
568f20eb55d4f8063f89c6c0abb3af3029fe23cb845Tadashi G. Takaoka        View v = mWords.get(index);
569e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        final int[] offsetInWindow = new int[2];
570e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        v.getLocationInWindow(offsetInWindow);
571e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        final int posX = offsetInWindow[0];
572e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        final int posY = offsetInWindow[1] - previewText.getMeasuredHeight();
573e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        final PopupWindow previewPopup = mPreviewPopup;
574e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        if (previewPopup.isShowing()) {
575e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka            previewPopup.update(posX, posY, previewPopup.getWidth(), previewPopup.getHeight());
576e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        } else {
577e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka            previewPopup.showAtLocation(this, Gravity.NO_GRAVITY, posX, posY);
578923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
579e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        previewText.setVisibility(VISIBLE);
58055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        mHandler.postHidePreview();
581923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
582fcba53ef7c874a4685c12c01404c91b779cae1e8Tadashi G. Takaoka
583e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka    private void addToDictionary(CharSequence word) {
584c97810693dfe83bf37c09f73c8d4b40f2ba8dddbTadashi G. Takaoka        if (mListener.addWordToDictionary(word.toString())) {
585e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka            showPreview(0, getContext().getString(R.string.added_word, word));
586e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        }
587e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka    }
588e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka
589e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka    @Override
590e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka    public boolean onLongClick(View view) {
59186e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        final Object tag = view.getTag();
59286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        if (!(tag instanceof Integer))
59386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka            return true;
59486e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        final int index = (Integer) tag;
59537deb112c727dfed5e94d054cf5f00f5d60c8120Tadashi G. Takaoka        if (index >= mSuggestions.size())
59637deb112c727dfed5e94d054cf5f00f5d60c8120Tadashi G. Takaoka            return true;
59786e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka
59837deb112c727dfed5e94d054cf5f00f5d60c8120Tadashi G. Takaoka        final CharSequence word = mSuggestions.getWord(index);
599e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        if (word.length() < 2)
600e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka            return false;
601e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        addToDictionary(word);
602e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka        return true;
603e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka    }
604e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka
605e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka    @Override
606e49bd1c43acad08f103b38430a8bbcba23f325b3Tadashi G. Takaoka    public void onClick(View view) {
607717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka        if (view == mWordToSave) {
608717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka            addToDictionary(((TextView)view).getText());
609717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka            clear();
610717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka            return;
611717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka        }
612717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka
61386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        final Object tag = view.getTag();
61486e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        if (!(tag instanceof Integer))
61586e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka            return;
61686e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        final int index = (Integer) tag;
61737deb112c727dfed5e94d054cf5f00f5d60c8120Tadashi G. Takaoka        if (index >= mSuggestions.size())
61837deb112c727dfed5e94d054cf5f00f5d60c8120Tadashi G. Takaoka            return;
61986e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka
62037deb112c727dfed5e94d054cf5f00f5d60c8120Tadashi G. Takaoka        final CharSequence word = mSuggestions.getWord(index);
621717a8f50aec421f74e4d43432059c2fb41cb32c7Tadashi G. Takaoka        mListener.pickSuggestionManually(index, word);
62286e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        // Because some punctuation letters are not treated as word separator depending on locale,
62386e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        // {@link #setSuggestions} might not be called and candidates pane left opened.
62486e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        closeCandidatesPane();
625923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
62682411d47ba7e8133ed2390c6920945e139a738cesatok
6276ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani    @Override
6286ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani    public void onDetachedFromWindow() {
6296ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani        super.onDetachedFromWindow();
63055b9d333c5d260cb5da3f6a2d872bda8c03478d7Tadashi G. Takaoka        mHandler.cancelAllMessages();
6316ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani        hidePreview();
6326ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani    }
633923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project}
634