SuggestionStripLayoutHelper.java revision 653603b7253d96c7fad674ed301de5bc8050b68c
1653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka/*
2653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka * Copyright (C) 2013 The Android Open Source Project
3653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka *
4653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka * Licensed under the Apache License, Version 2.0 (the "License");
5653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka * you may not use this file except in compliance with the License.
6653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka * You may obtain a copy of the License at
7653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka *
8653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka *      http://www.apache.org/licenses/LICENSE-2.0
9653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka *
10653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka * Unless required by applicable law or agreed to in writing, software
11653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka * distributed under the License is distributed on an "AS IS" BASIS,
12653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka * See the License for the specific language governing permissions and
14653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka * limitations under the License.
15653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka */
16653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka
17653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaokapackage com.android.inputmethod.latin.suggestions;
18653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka
19653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaokaimport android.content.Context;
20653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaokaimport android.content.res.Resources;
21653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaokaimport android.content.res.TypedArray;
22653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaokaimport android.graphics.Bitmap;
23653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaokaimport android.graphics.Canvas;
24653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaokaimport android.graphics.Color;
25653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaokaimport android.graphics.Paint;
26653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaokaimport android.graphics.Rect;
27653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaokaimport android.graphics.Typeface;
28653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaokaimport android.graphics.Paint.Align;
29653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaokaimport android.graphics.drawable.BitmapDrawable;
30653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaokaimport android.graphics.drawable.Drawable;
31653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaokaimport android.text.Spannable;
32653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaokaimport android.text.SpannableString;
33653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaokaimport android.text.Spanned;
34653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaokaimport android.text.TextPaint;
35653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaokaimport android.text.TextUtils;
36653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaokaimport android.text.style.CharacterStyle;
37653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaokaimport android.text.style.StyleSpan;
38653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaokaimport android.text.style.UnderlineSpan;
39653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaokaimport android.util.AttributeSet;
40653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaokaimport android.view.Gravity;
41653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaokaimport android.view.LayoutInflater;
42653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaokaimport android.view.View;
43653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaokaimport android.view.ViewGroup;
44653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaokaimport android.view.View.OnClickListener;
45653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaokaimport android.widget.LinearLayout;
46653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaokaimport android.widget.TextView;
47653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka
48653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaokaimport com.android.inputmethod.keyboard.ViewLayoutUtils;
49653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaokaimport com.android.inputmethod.latin.AutoCorrection;
50653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaokaimport com.android.inputmethod.latin.CollectionUtils;
51653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaokaimport com.android.inputmethod.latin.LatinImeLogger;
52653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaokaimport com.android.inputmethod.latin.R;
53653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaokaimport com.android.inputmethod.latin.ResourceUtils;
54653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaokaimport com.android.inputmethod.latin.SuggestedWords;
55653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaokaimport com.android.inputmethod.latin.Utils;
56653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka
57653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaokaimport java.util.ArrayList;
58653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka
59653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaokafinal class SuggestionStripLayoutHelper {
60653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    private static final int DEFAULT_SUGGESTIONS_COUNT_IN_STRIP = 3;
61653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    private static final float DEFAULT_CENTER_SUGGESTION_PERCENTILE = 0.40f;
62653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    private static final int DEFAULT_MAX_MORE_SUGGESTIONS_ROW = 2;
63653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    private static final int PUNCTUATIONS_IN_STRIP = 5;
64653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    private static final float MIN_TEXT_XSCALE = 0.70f;
65653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka
66653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    public final int mPadding;
67653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    public final int mDividerWidth;
68653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    public final int mSuggestionsStripHeight;
69653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    public final int mSuggestionsCountInStrip;
70653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    public final int mMoreSuggestionsRowHeight;
71653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    private int mMaxMoreSuggestionsRow;
72653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    public final float mMinMoreSuggestionsWidth;
73653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    public final int mMoreSuggestionsBottomGap;
74653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka
75653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    private final ArrayList<TextView> mWords;
76653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    private final ArrayList<View> mDividers;
77653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    private final ArrayList<TextView> mInfos;
78653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka
79653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    private final int mColorValidTypedWord;
80653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    private final int mColorTypedWord;
81653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    private final int mColorAutoCorrect;
82653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    private final int mColorSuggested;
83653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    private final float mAlphaObsoleted;
84653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    private final float mCenterSuggestionWeight;
85653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    private final int mCenterSuggestionIndex;
86653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    private final Drawable mMoreSuggestionsHint;
87653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    private static final String MORE_SUGGESTIONS_HINT = "\u2026";
88653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    private static final String LEFTWARDS_ARROW = "\u2190";
89653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka
90653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    private static final CharacterStyle BOLD_SPAN = new StyleSpan(Typeface.BOLD);
91653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    private static final CharacterStyle UNDERLINE_SPAN = new UnderlineSpan();
92653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    private static final int AUTO_CORRECT_BOLD = 0x01;
93653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    private static final int AUTO_CORRECT_UNDERLINE = 0x02;
94653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    private static final int VALID_TYPED_WORD_BOLD = 0x04;
95653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka
96653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    private final int mSuggestionStripOption;
97653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka
98653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    private final ArrayList<CharSequence> mTexts = CollectionUtils.newArrayList();
99653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka
100653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    public boolean mMoreSuggestionsAvailable;
101653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka
102653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    private final TextView mWordToSaveView;
103653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    private final TextView mLeftwardsArrowView;
104653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    private final TextView mHintToSaveView;
105653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka
106653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    public SuggestionStripLayoutHelper(final Context context, final AttributeSet attrs,
107653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka            final int defStyle, final ArrayList<TextView> words, final ArrayList<View> dividers,
108653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka            final ArrayList<TextView> infos) {
109653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        mWords = words;
110653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        mDividers = dividers;
111653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        mInfos = infos;
112653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka
113653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        final TextView word = words.get(0);
114653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        final View divider = dividers.get(0);
115653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        mPadding = word.getCompoundPaddingLeft() + word.getCompoundPaddingRight();
116653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        divider.measure(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
117653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        mDividerWidth = divider.getMeasuredWidth();
118653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka
119653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        final Resources res = word.getResources();
120653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        mSuggestionsStripHeight = res.getDimensionPixelSize(R.dimen.suggestions_strip_height);
121653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka
122653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        final TypedArray a = context.obtainStyledAttributes(attrs,
123653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka                R.styleable.SuggestionStripView, defStyle, R.style.SuggestionStripViewStyle);
124653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        mSuggestionStripOption = a.getInt(
125653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka                R.styleable.SuggestionStripView_suggestionStripOption, 0);
126653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        final float alphaValidTypedWord = ResourceUtils.getFraction(a,
127653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka                R.styleable.SuggestionStripView_alphaValidTypedWord, 1.0f);
128653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        final float alphaTypedWord = ResourceUtils.getFraction(a,
129653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka                R.styleable.SuggestionStripView_alphaTypedWord, 1.0f);
130653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        final float alphaAutoCorrect = ResourceUtils.getFraction(a,
131653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka                R.styleable.SuggestionStripView_alphaAutoCorrect, 1.0f);
132653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        final float alphaSuggested = ResourceUtils.getFraction(a,
133653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka                R.styleable.SuggestionStripView_alphaSuggested, 1.0f);
134653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        mAlphaObsoleted = ResourceUtils.getFraction(a,
135653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka                R.styleable.SuggestionStripView_alphaSuggested, 1.0f);
136653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        mColorValidTypedWord = applyAlpha(a.getColor(
137653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka                R.styleable.SuggestionStripView_colorValidTypedWord, 0), alphaValidTypedWord);
138653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        mColorTypedWord = applyAlpha(a.getColor(
139653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka                R.styleable.SuggestionStripView_colorTypedWord, 0), alphaTypedWord);
140653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        mColorAutoCorrect = applyAlpha(a.getColor(
141653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka                R.styleable.SuggestionStripView_colorAutoCorrect, 0), alphaAutoCorrect);
142653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        mColorSuggested = applyAlpha(a.getColor(
143653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka                R.styleable.SuggestionStripView_colorSuggested, 0), alphaSuggested);
144653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        mSuggestionsCountInStrip = a.getInt(
145653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka                R.styleable.SuggestionStripView_suggestionsCountInStrip,
146653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka                DEFAULT_SUGGESTIONS_COUNT_IN_STRIP);
147653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        mCenterSuggestionWeight = ResourceUtils.getFraction(a,
148653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka                R.styleable.SuggestionStripView_centerSuggestionPercentile,
149653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka                DEFAULT_CENTER_SUGGESTION_PERCENTILE);
150653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        mMaxMoreSuggestionsRow = a.getInt(
151653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka                R.styleable.SuggestionStripView_maxMoreSuggestionsRow,
152653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka                DEFAULT_MAX_MORE_SUGGESTIONS_ROW);
153653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        mMinMoreSuggestionsWidth = ResourceUtils.getFraction(a,
154653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka                R.styleable.SuggestionStripView_minMoreSuggestionsWidth, 1.0f);
155653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        a.recycle();
156653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka
157653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        mMoreSuggestionsHint = getMoreSuggestionsHint(res,
158653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka                res.getDimension(R.dimen.more_suggestions_hint_text_size), mColorAutoCorrect);
159653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        mCenterSuggestionIndex = mSuggestionsCountInStrip / 2;
160653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        mMoreSuggestionsBottomGap = res.getDimensionPixelOffset(
161653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka                R.dimen.more_suggestions_bottom_gap);
162653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        mMoreSuggestionsRowHeight = res.getDimensionPixelSize(R.dimen.more_suggestions_row_height);
163653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka
164653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        final LayoutInflater inflater = LayoutInflater.from(context);
165653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        mWordToSaveView = (TextView)inflater.inflate(R.layout.suggestion_word, null);
166653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        mLeftwardsArrowView = (TextView)inflater.inflate(R.layout.hint_add_to_dictionary, null);
167653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        mHintToSaveView = (TextView)inflater.inflate(R.layout.hint_add_to_dictionary, null);
168653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    }
169653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka
170653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    public int getMaxMoreSuggestionsRow() {
171653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        return mMaxMoreSuggestionsRow;
172653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    }
173653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka
174653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    private int getMoreSuggestionsHeight() {
175653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        return mMaxMoreSuggestionsRow * mMoreSuggestionsRowHeight + mMoreSuggestionsBottomGap;
176653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    }
177653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka
178653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    public int setMoreSuggestionsHeight(final int remainingHeight) {
179653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        final int currentHeight = getMoreSuggestionsHeight();
180653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        if (currentHeight <= remainingHeight) {
181653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka            return currentHeight;
182653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        }
183653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka
184653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        mMaxMoreSuggestionsRow = (remainingHeight - mMoreSuggestionsBottomGap)
185653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka                / mMoreSuggestionsRowHeight;
186653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        final int newHeight = getMoreSuggestionsHeight();
187653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        return newHeight;
188653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    }
189653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka
190653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    private static Drawable getMoreSuggestionsHint(final Resources res, final float textSize,
191653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka            final int color) {
192653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        final Paint paint = new Paint();
193653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        paint.setAntiAlias(true);
194653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        paint.setTextAlign(Align.CENTER);
195653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        paint.setTextSize(textSize);
196653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        paint.setColor(color);
197653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        final Rect bounds = new Rect();
198653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        paint.getTextBounds(MORE_SUGGESTIONS_HINT, 0, MORE_SUGGESTIONS_HINT.length(), bounds);
199653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        final int width = Math.round(bounds.width() + 0.5f);
200653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        final int height = Math.round(bounds.height() + 0.5f);
201653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        final Bitmap buffer = Bitmap.createBitmap(width, (height * 3 / 2), Bitmap.Config.ARGB_8888);
202653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        final Canvas canvas = new Canvas(buffer);
203653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        canvas.drawText(MORE_SUGGESTIONS_HINT, width / 2, height, paint);
204653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        return new BitmapDrawable(res, buffer);
205653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    }
206653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka
207653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    private CharSequence getStyledSuggestionWord(final SuggestedWords suggestedWords,
208653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka            final int indexInSuggestedWords) {
209653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        final String word = suggestedWords.getWord(indexInSuggestedWords);
210653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        final boolean isAutoCorrect = indexInSuggestedWords == 1
211653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka                && suggestedWords.willAutoCorrect();
212653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        final boolean isTypedWordValid = indexInSuggestedWords == 0
213653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka                && suggestedWords.mTypedWordValid;
214653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        if (!isAutoCorrect && !isTypedWordValid)
215653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka            return word;
216653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka
217653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        final int len = word.length();
218653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        final Spannable spannedWord = new SpannableString(word);
219653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        final int option = mSuggestionStripOption;
220653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        if ((isAutoCorrect && (option & AUTO_CORRECT_BOLD) != 0)
221653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka                || (isTypedWordValid && (option & VALID_TYPED_WORD_BOLD) != 0)) {
222653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka            spannedWord.setSpan(BOLD_SPAN, 0, len, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
223653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        }
224653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        if (isAutoCorrect && (option & AUTO_CORRECT_UNDERLINE) != 0) {
225653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka            spannedWord.setSpan(UNDERLINE_SPAN, 0, len, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
226653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        }
227653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        return spannedWord;
228653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    }
229653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka
230653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    private int getIndexInSuggestedWords(final int indexInStrip,
231653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka            final SuggestedWords suggestedWords) {
232653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        // TODO: This works for 3 suggestions. Revisit this algorithm when there are 5 or more
233653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        // suggestions.
234653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        final int mostImportantIndexInSuggestedWords = suggestedWords.willAutoCorrect() ? 1 : 0;
235653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        if (indexInStrip == mCenterSuggestionIndex) {
236653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka            return mostImportantIndexInSuggestedWords;
237653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        } else if (indexInStrip == mostImportantIndexInSuggestedWords) {
238653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka            return mCenterSuggestionIndex;
239653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        } else {
240653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka            return indexInStrip;
241653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        }
242653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    }
243653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka
244653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    private int getSuggestionTextColor(final int indexInStrip,
245653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka            final SuggestedWords suggestedWords) {
246653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        final int indexInSuggestedWords = getIndexInSuggestedWords(
247653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka                indexInStrip, suggestedWords);
248653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        // TODO: Need to revisit this logic with bigram suggestions
249653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        final boolean isSuggested = (indexInSuggestedWords != 0);
250653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka
251653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        final int color;
252653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        if (indexInStrip == mCenterSuggestionIndex && suggestedWords.willAutoCorrect()) {
253653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka            color = mColorAutoCorrect;
254653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        } else if (indexInStrip == mCenterSuggestionIndex && suggestedWords.mTypedWordValid) {
255653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka            color = mColorValidTypedWord;
256653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        } else if (isSuggested) {
257653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka            color = mColorSuggested;
258653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        } else {
259653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka            color = mColorTypedWord;
260653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        }
261653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        if (LatinImeLogger.sDBG && suggestedWords.size() > 1) {
262653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka            // If we auto-correct, then the autocorrection is in slot 0 and the typed word
263653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka            // is in slot 1.
264653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka            if (indexInStrip == mCenterSuggestionIndex
265653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka                    && AutoCorrection.shouldBlockAutoCorrectionBySafetyNet(
266653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka                            suggestedWords.getWord(1), suggestedWords.getWord(0))) {
267653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka                return 0xFFFF0000;
268653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka            }
269653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        }
270653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka
271653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        if (suggestedWords.mIsObsoleteSuggestions && isSuggested) {
272653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka            return applyAlpha(color, mAlphaObsoleted);
273653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        } else {
274653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka            return color;
275653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        }
276653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    }
277653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka
278653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    private static int applyAlpha(final int color, final float alpha) {
279653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        final int newAlpha = (int)(Color.alpha(color) * alpha);
280653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        return Color.argb(newAlpha, Color.red(color), Color.green(color), Color.blue(color));
281653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    }
282653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka
283653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    private static void addDivider(final ViewGroup stripView, final View divider) {
284653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        stripView.addView(divider);
285653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        final LinearLayout.LayoutParams params =
286653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka                (LinearLayout.LayoutParams)divider.getLayoutParams();
287653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        params.gravity = Gravity.CENTER;
288653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    }
289653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka
290653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    public void layout(final SuggestedWords suggestedWords, final ViewGroup stripView,
291653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka            final ViewGroup placer, final int stripWidth) {
292653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        if (suggestedWords.mIsPunctuationSuggestions) {
293653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka            layoutPunctuationSuggestions(suggestedWords, stripView);
294653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka            return;
295653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        }
296653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka
297653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        final int countInStrip = mSuggestionsCountInStrip;
298653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        setupTexts(suggestedWords, countInStrip);
299653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        mMoreSuggestionsAvailable = (suggestedWords.size() > countInStrip);
300653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        int x = 0;
301653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        for (int indexInStrip = 0; indexInStrip < countInStrip; indexInStrip++) {
302653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka            if (indexInStrip != 0) {
303653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka                final View divider = mDividers.get(indexInStrip);
304653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka                // Add divider if this isn't the left most suggestion in suggestions strip.
305653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka                addDivider(stripView, divider);
306653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka                x += divider.getMeasuredWidth();
307653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka            }
308653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka
309653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka            final int width = getSuggestionWidth(indexInStrip, stripWidth);
310653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka            final TextView word = layoutWord(suggestedWords, indexInStrip, width);
311653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka            stripView.addView(word);
312653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka            setLayoutWeight(word, getSuggestionWeight(indexInStrip),
313653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka                    ViewGroup.LayoutParams.MATCH_PARENT);
314653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka            x += word.getMeasuredWidth();
315653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka
316653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka            if (SuggestionStripView.DBG) {
317653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka                layoutDebugInfo(suggestedWords, indexInStrip, placer, x);
318653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka            }
319653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        }
320653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    }
321653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka
322653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    /**
323653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka     * Format appropriately the suggested word indirectly specified by
324653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka     * <code>indexInStrip</code> as text in a corresponding {@link TextView}. When the
325653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka     * suggested word doesn't exist, the corresponding {@link TextView} will be disabled
326653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka     * and never respond to user interaction. The suggested word may be shrunk or ellipsized to
327653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka     * fit in the specified width.
328653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka     *
329653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka     * The <code>indexInStrip</code> argument is the index in the suggestion strip. The indices
330653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka     * increase towards the right for LTR scripts and the left for RTL scripts, starting with 0.
331653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka     * The index of the most important suggestion is in {@link #mCenterSuggestionIndex}. This
332653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka     * usually doesn't match the index in <code>suggedtedWords</code> -- see
333653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka     * {@link #getIndexInSuggestedWords(int,SuggestedWords)}.
334653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka     *
335653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka     * @param suggestedWords the list of suggestions.
336653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka     * @param indexInStrip the in the suggestion strip.
337653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka     * @param width the maximum width for layout in pixels.
338653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka     * @return the {@link TextView} containing the suggested word appropriately formatted.
339653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka     */
340653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    private TextView layoutWord(final SuggestedWords suggestedWords, final int indexInStrip,
341653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka            final int width) {
342653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        final int indexInSuggestedWords = getIndexInSuggestedWords(indexInStrip, suggestedWords);
343653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        final CharSequence styled = mTexts.get(indexInSuggestedWords);
344653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        final TextView word = mWords.get(indexInSuggestedWords);
345653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        if (indexInStrip == mCenterSuggestionIndex && mMoreSuggestionsAvailable) {
346653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka            // TODO: This "more suggestions hint" should have a nicely designed icon.
347653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka            word.setCompoundDrawablesWithIntrinsicBounds(
348653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka                    null, null, null, mMoreSuggestionsHint);
349653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka            // HACK: Align with other TextViews that have no compound drawables.
350653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka            word.setCompoundDrawablePadding(-mMoreSuggestionsHint.getIntrinsicHeight());
351653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        } else {
352653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka            word.setCompoundDrawablesWithIntrinsicBounds(null, null, null, null);
353653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        }
354653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka
355653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        // Disable this suggestion if the suggestion is null or empty.
356653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        word.setEnabled(!TextUtils.isEmpty(styled));
357653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        word.setTextColor(getSuggestionTextColor(indexInStrip, suggestedWords));
358653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        final CharSequence text = getEllipsizedText(styled, width, word.getPaint());
359653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        final float scaleX = word.getTextScaleX();
360653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        word.setText(text); // TextView.setText() resets text scale x to 1.0.
361653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        word.setTextScaleX(scaleX);
362653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        return word;
363653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    }
364653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka
365653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    private void layoutDebugInfo(final SuggestedWords suggestedWords, final int indexInStrip,
366653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka            final ViewGroup placer, final int x) {
367653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        final int indexInSuggestedWords = getIndexInSuggestedWords(indexInStrip, suggestedWords);
368653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        if (indexInSuggestedWords >= suggestedWords.size()) {
369653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka            return;
370653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        }
371653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        final String debugInfo = Utils.getDebugInfo(suggestedWords, indexInSuggestedWords);
372653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        if (debugInfo == null) {
373653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka            return;
374653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        }
375653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        final TextView info = mInfos.get(indexInSuggestedWords);
376653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        info.setText(debugInfo);
377653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        placer.addView(info);
378653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        info.measure(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
379653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        final int infoWidth = info.getMeasuredWidth();
380653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        final int y = info.getMeasuredHeight();
381653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        ViewLayoutUtils.placeViewAt(
382653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka                info, x - infoWidth, y, infoWidth, info.getMeasuredHeight());
383653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    }
384653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka
385653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    private int getSuggestionWidth(final int indexInStrip, final int maxWidth) {
386653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        final int paddings = mPadding * mSuggestionsCountInStrip;
387653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        final int dividers = mDividerWidth * (mSuggestionsCountInStrip - 1);
388653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        final int availableWidth = maxWidth - paddings - dividers;
389653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        return (int)(availableWidth * getSuggestionWeight(indexInStrip));
390653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    }
391653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka
392653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    private float getSuggestionWeight(final int indexInStrip) {
393653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        if (indexInStrip == mCenterSuggestionIndex) {
394653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka            return mCenterSuggestionWeight;
395653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        } else {
396653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka            // TODO: Revisit this for cases of 5 or more suggestions
397653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka            return (1.0f - mCenterSuggestionWeight) / (mSuggestionsCountInStrip - 1);
398653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        }
399653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    }
400653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka
401653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    private void setupTexts(final SuggestedWords suggestedWords, final int countInStrip) {
402653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        mTexts.clear();
403653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        final int count = Math.min(suggestedWords.size(), countInStrip);
404653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        for (int pos = 0; pos < count; pos++) {
405653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka            final CharSequence styled = getStyledSuggestionWord(suggestedWords, pos);
406653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka            mTexts.add(styled);
407653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        }
408653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        for (int pos = count; pos < countInStrip; pos++) {
409653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka            // Make this inactive for touches in layout().
410653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka            mTexts.add(null);
411653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        }
412653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    }
413653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka
414653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    private void layoutPunctuationSuggestions(final SuggestedWords suggestedWords,
415653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka            final ViewGroup stripView) {
416653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        final int countInStrip = Math.min(suggestedWords.size(), PUNCTUATIONS_IN_STRIP);
417653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        for (int indexInStrip = 0; indexInStrip < countInStrip; indexInStrip++) {
418653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka            if (indexInStrip != 0) {
419653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka                // Add divider if this isn't the left most suggestion in suggestions strip.
420653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka                addDivider(stripView, mDividers.get(indexInStrip));
421653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka            }
422653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka
423653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka            final TextView word = mWords.get(indexInStrip);
424653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka            word.setEnabled(true);
425653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka            word.setTextColor(mColorAutoCorrect);
426653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka            final String text = suggestedWords.getWord(indexInStrip);
427653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka            word.setText(text);
428653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka            word.setTextScaleX(1.0f);
429653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka            word.setCompoundDrawables(null, null, null, null);
430653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka            stripView.addView(word);
431653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka            setLayoutWeight(word, 1.0f, mSuggestionsStripHeight);
432653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        }
433653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        mMoreSuggestionsAvailable = false;
434653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    }
435653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka
436653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    public void layoutAddToDictionaryHint(final String word, final ViewGroup stripView,
437653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka            final int stripWidth, final CharSequence hintText, final OnClickListener listener) {
438653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        final int width = stripWidth - mDividerWidth - mPadding * 2;
439653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka
440653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        final TextView wordView = mWordToSaveView;
441653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        wordView.setTextColor(mColorTypedWord);
442653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        final int wordWidth = (int)(width * mCenterSuggestionWeight);
443653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        final CharSequence text = getEllipsizedText(word, wordWidth, wordView.getPaint());
444653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        final float wordScaleX = wordView.getTextScaleX();
445653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        wordView.setTag(word);
446653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        wordView.setText(text);
447653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        wordView.setTextScaleX(wordScaleX);
448653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        stripView.addView(wordView);
449653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        setLayoutWeight(wordView, mCenterSuggestionWeight, ViewGroup.LayoutParams.MATCH_PARENT);
450653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka
451653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        stripView.addView(mDividers.get(0));
452653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka
453653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        final TextView leftArrowView = mLeftwardsArrowView;
454653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        leftArrowView.setTextColor(mColorAutoCorrect);
455653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        leftArrowView.setText(LEFTWARDS_ARROW);
456653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        stripView.addView(leftArrowView);
457653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka
458653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        final TextView hintView = mHintToSaveView;
459653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        hintView.setGravity(Gravity.LEFT | Gravity.CENTER_VERTICAL);
460653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        hintView.setTextColor(mColorAutoCorrect);
461653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        final int hintWidth = width - wordWidth - leftArrowView.getWidth();
462653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        final float hintScaleX = getTextScaleX(hintText, hintWidth, hintView.getPaint());
463653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        hintView.setText(hintText);
464653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        hintView.setTextScaleX(hintScaleX);
465653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        stripView.addView(hintView);
466653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        setLayoutWeight(
467653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka                hintView, 1.0f - mCenterSuggestionWeight, ViewGroup.LayoutParams.MATCH_PARENT);
468653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka
469653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        wordView.setOnClickListener(listener);
470653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        leftArrowView.setOnClickListener(listener);
471653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        hintView.setOnClickListener(listener);
472653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    }
473653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka
474653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    public CharSequence getAddToDictionaryWord() {
475653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        return (CharSequence)mWordToSaveView.getTag();
476653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    }
477653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka
478653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    public boolean isAddToDictionaryShowing(final View v) {
479653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        return v == mWordToSaveView || v == mHintToSaveView || v == mLeftwardsArrowView;
480653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    }
481653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka
482653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    private static void setLayoutWeight(final View v, final float weight, final int height) {
483653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        final ViewGroup.LayoutParams lp = v.getLayoutParams();
484653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        if (lp instanceof LinearLayout.LayoutParams) {
485653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka            final LinearLayout.LayoutParams llp = (LinearLayout.LayoutParams)lp;
486653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka            llp.weight = weight;
487653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka            llp.width = 0;
488653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka            llp.height = height;
489653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        }
490653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    }
491653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka
492653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    private static float getTextScaleX(final CharSequence text, final int maxWidth,
493653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka            final TextPaint paint) {
494653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        paint.setTextScaleX(1.0f);
495653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        final int width = getTextWidth(text, paint);
496653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        if (width <= maxWidth) {
497653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka            return 1.0f;
498653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        }
499653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        return maxWidth / (float)width;
500653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    }
501653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka
502653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    private static CharSequence getEllipsizedText(final CharSequence text, final int maxWidth,
503653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka            final TextPaint paint) {
504653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        if (text == null) return null;
505653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        paint.setTextScaleX(1.0f);
506653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        final int width = getTextWidth(text, paint);
507653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        if (width <= maxWidth) {
508653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka            return text;
509653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        }
510653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        final float scaleX = maxWidth / (float)width;
511653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        if (scaleX >= MIN_TEXT_XSCALE) {
512653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka            paint.setTextScaleX(scaleX);
513653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka            return text;
514653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        }
515653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka
516653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        // Note that TextUtils.ellipsize() use text-x-scale as 1.0 if ellipsize is needed. To
517653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        // get squeezed and ellipsized text, passes enlarged width (maxWidth / MIN_TEXT_XSCALE).
518653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        final CharSequence ellipsized = TextUtils.ellipsize(
519653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka                text, paint, maxWidth / MIN_TEXT_XSCALE, TextUtils.TruncateAt.MIDDLE);
520653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        paint.setTextScaleX(MIN_TEXT_XSCALE);
521653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        return ellipsized;
522653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    }
523653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka
524653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    private static int getTextWidth(final CharSequence text, final TextPaint paint) {
525653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        if (TextUtils.isEmpty(text)) return 0;
526653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        final Typeface savedTypeface = paint.getTypeface();
527653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        paint.setTypeface(getTextTypeface(text));
528653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        final int len = text.length();
529653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        final float[] widths = new float[len];
530653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        final int count = paint.getTextWidths(text, 0, len, widths);
531653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        int width = 0;
532653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        for (int i = 0; i < count; i++) {
533653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka            width += Math.round(widths[i] + 0.5f);
534653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        }
535653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        paint.setTypeface(savedTypeface);
536653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        return width;
537653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    }
538653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka
539653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    private static Typeface getTextTypeface(final CharSequence text) {
540653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        if (!(text instanceof SpannableString))
541653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka            return Typeface.DEFAULT;
542653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka
543653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        final SpannableString ss = (SpannableString)text;
544653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        final StyleSpan[] styles = ss.getSpans(0, text.length(), StyleSpan.class);
545653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        if (styles.length == 0)
546653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka            return Typeface.DEFAULT;
547653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka
548653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        switch (styles[0].getStyle()) {
549653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        case Typeface.BOLD: return Typeface.DEFAULT_BOLD;
550653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        // TODO: BOLD_ITALIC, ITALIC case?
551653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        default: return Typeface.DEFAULT;
552653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka        }
553653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka    }
554653603b7253d96c7fad674ed301de5bc8050b68cTadashi G. Takaoka}
555