SuggestionStripView.java revision 6558253160e2039c87f424bd814f402ecd31de3b
1923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project/*
2923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Copyright (C) 2008-2009 Google Inc.
3923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project *
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
7923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project *
8923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0
9923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project *
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 java.util.ArrayList;
20923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport java.util.Arrays;
21923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport java.util.List;
22923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
23923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.content.Context;
2466a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasaniimport android.content.res.Resources;
25923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.graphics.Canvas;
26923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.graphics.Paint;
27923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.graphics.Rect;
28923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.graphics.Typeface;
296a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasaniimport android.graphics.Paint.Align;
30923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.graphics.drawable.Drawable;
31923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.os.Handler;
32923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.os.Message;
33923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.util.AttributeSet;
34923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.GestureDetector;
35923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.Gravity;
36923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.LayoutInflater;
37923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.MotionEvent;
38923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.View;
39923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.view.ViewGroup.LayoutParams;
40923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.widget.PopupWindow;
41923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport android.widget.TextView;
42923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
43923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectpublic class CandidateView extends View {
44923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
45923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private static final int OUT_OF_BOUNDS = -1;
46923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private static final List<CharSequence> EMPTY_LIST = new ArrayList<CharSequence>();
47923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
48923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private LatinIME mService;
49923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private List<CharSequence> mSuggestions = EMPTY_LIST;
50923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private boolean mShowingCompletions;
51923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private CharSequence mSelectedString;
52923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private int mSelectedIndex;
53923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private int mTouchX = OUT_OF_BOUNDS;
54923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private Drawable mSelectionHighlight;
55923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private boolean mTypedWordValid;
56923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
57923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private boolean mHaveMinimalSuggestion;
58923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
59923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private Rect mBgPadding;
60923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
61923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private TextView mPreviewText;
62923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private PopupWindow mPreviewPopup;
63923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private int mCurrentWordIndex;
64923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private Drawable mDivider;
65923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
66923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private static final int MAX_SUGGESTIONS = 32;
67923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private static final int SCROLL_PIXELS = 20;
68923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
69923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private static final int MSG_REMOVE_PREVIEW = 1;
70923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private static final int MSG_REMOVE_THROUGH_PREVIEW = 2;
71923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
72923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private int[] mWordWidth = new int[MAX_SUGGESTIONS];
73923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private int[] mWordX = new int[MAX_SUGGESTIONS];
74923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private int mPopupPreviewX;
75923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private int mPopupPreviewY;
76923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
77923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private static final int X_GAP = 10;
78923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
79923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private int mColorNormal;
80923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private int mColorRecommended;
81923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private int mColorOther;
82923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private Paint mPaint;
83923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private int mDescent;
84923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private boolean mScrolled;
8566a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani    private boolean mShowingAddToDictionary;
8666a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani    private CharSequence mWordToAddToDictionary;
8766a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani    private CharSequence mAddToDictionaryHint;
8866a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani
89923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private int mTargetScrollX;
906a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani
916a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani    private int mMinTouchableWidth;
926a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani
93923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private int mTotalWidth;
94923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
95923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private GestureDetector mGestureDetector;
96923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
97923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    Handler mHandler = new Handler() {
98923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        @Override
99923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        public void handleMessage(Message msg) {
100923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            switch (msg.what) {
101923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                case MSG_REMOVE_PREVIEW:
102923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    mPreviewText.setVisibility(GONE);
103923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    break;
104923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                case MSG_REMOVE_THROUGH_PREVIEW:
105923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    mPreviewText.setVisibility(GONE);
106923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    if (mTouchX != OUT_OF_BOUNDS) {
107923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                        removeHighlight();
108923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    }
109923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    break;
110923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
111923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
112923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
113923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    };
114923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
115923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    /**
116923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     * Construct a CandidateView for showing suggested words for completion.
117923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     * @param context
118923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     * @param attrs
119923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     */
120923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public CandidateView(Context context, AttributeSet attrs) {
121923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        super(context, attrs);
122923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mSelectionHighlight = context.getResources().getDrawable(
123466741d8a78965b8509bf527344f289e50873092Mike LeBeau                R.drawable.list_selector_background_pressed);
124923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
125923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        LayoutInflater inflate =
126923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            (LayoutInflater) context
127923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
12866a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani        Resources res = context.getResources();
129923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mPreviewPopup = new PopupWindow(context);
130923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mPreviewText = (TextView) inflate.inflate(R.layout.candidate_preview, null);
131923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mPreviewPopup.setWindowLayoutMode(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
132923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mPreviewPopup.setContentView(mPreviewText);
133923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mPreviewPopup.setBackgroundDrawable(null);
13466a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani        mColorNormal = res.getColor(R.color.candidate_normal);
13566a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani        mColorRecommended = res.getColor(R.color.candidate_recommended);
13666a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani        mColorOther = res.getColor(R.color.candidate_other);
13766a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani        mDivider = res.getDrawable(R.drawable.keyboard_suggest_strip_divider);
13866a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani        mAddToDictionaryHint = res.getString(R.string.hint_add_to_dictionary);
139923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
140923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mPaint = new Paint();
141923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mPaint.setColor(mColorNormal);
142923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mPaint.setAntiAlias(true);
143923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mPaint.setTextSize(mPreviewText.getTextSize());
144923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mPaint.setStrokeWidth(0);
1456a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani        mPaint.setTextAlign(Align.CENTER);
146923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mDescent = (int) mPaint.descent();
1476a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani        // 80 pixels for a 160dpi device would mean half an inch
1486a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani        mMinTouchableWidth = (int) (getResources().getDisplayMetrics().density * 50);
149923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
150923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mGestureDetector = new GestureDetector(new GestureDetector.SimpleOnGestureListener() {
151923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            @Override
152923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            public void onLongPress(MotionEvent me) {
153923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                if (mSuggestions.size() > 0) {
1547a722cbfc8bbb8a7b260895266a0fd3a9baf1994Amith Yamasani                    if (me.getX() + getScrollX() < mWordWidth[0] && getScrollX() < 10) {
155923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                        longPressFirstWord();
156923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    }
157923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                }
158923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
159923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
160923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            @Override
161923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            public boolean onScroll(MotionEvent e1, MotionEvent e2,
162923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    float distanceX, float distanceY) {
1636ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani                final int width = getWidth();
164923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                mScrolled = true;
1657a722cbfc8bbb8a7b260895266a0fd3a9baf1994Amith Yamasani                int scrollX = getScrollX();
1667a722cbfc8bbb8a7b260895266a0fd3a9baf1994Amith Yamasani                scrollX += (int) distanceX;
1677a722cbfc8bbb8a7b260895266a0fd3a9baf1994Amith Yamasani                if (scrollX < 0) {
1687a722cbfc8bbb8a7b260895266a0fd3a9baf1994Amith Yamasani                    scrollX = 0;
169923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                }
1707a722cbfc8bbb8a7b260895266a0fd3a9baf1994Amith Yamasani                if (distanceX > 0 && scrollX + width > mTotalWidth) {
1717a722cbfc8bbb8a7b260895266a0fd3a9baf1994Amith Yamasani                    scrollX -= (int) distanceX;
172923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                }
1737a722cbfc8bbb8a7b260895266a0fd3a9baf1994Amith Yamasani                mTargetScrollX = scrollX;
1747a722cbfc8bbb8a7b260895266a0fd3a9baf1994Amith Yamasani                scrollTo(scrollX, getScrollY());
1756ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani                hidePreview();
176923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                invalidate();
177923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                return true;
178923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
179923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        });
180923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        setHorizontalFadingEdgeEnabled(true);
181923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        setWillNotDraw(false);
182923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        setHorizontalScrollBarEnabled(false);
183923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        setVerticalScrollBarEnabled(false);
1847a722cbfc8bbb8a7b260895266a0fd3a9baf1994Amith Yamasani        scrollTo(0, getScrollY());
185923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
186923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
187923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    /**
188923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     * A connection back to the service to communicate with the text field
189923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     * @param listener
190923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     */
191923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void setService(LatinIME listener) {
192923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mService = listener;
193923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
194923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
195923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
196923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public int computeHorizontalScrollRange() {
197923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        return mTotalWidth;
198923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
199923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
200923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    /**
201923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     * If the canvas is null, then only touch calculations are performed to pick the target
202923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     * candidate.
203923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     */
204923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
205923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    protected void onDraw(Canvas canvas) {
206923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (canvas != null) {
207923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            super.onDraw(canvas);
208923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
209923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mTotalWidth = 0;
210923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (mSuggestions == null) return;
211923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
212923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        final int height = getHeight();
213923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (mBgPadding == null) {
214923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mBgPadding = new Rect(0, 0, 0, 0);
215923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (getBackground() != null) {
216923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                getBackground().getPadding(mBgPadding);
217923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
2186a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani            mDivider.setBounds(0, 0, mDivider.getIntrinsicWidth(),
219923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    mDivider.getIntrinsicHeight());
220923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
221923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        int x = 0;
222923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        final int count = mSuggestions.size();
223923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        final int width = getWidth();
224923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        final Rect bgPadding = mBgPadding;
225923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        final Paint paint = mPaint;
226923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        final int touchX = mTouchX;
2277a722cbfc8bbb8a7b260895266a0fd3a9baf1994Amith Yamasani        final int scrollX = getScrollX();
228923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        final boolean scrolled = mScrolled;
229923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        final boolean typedWordValid = mTypedWordValid;
230923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        final int y = (int) (height + mPaint.getTextSize() - mDescent) / 2;
231923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
232923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        for (int i = 0; i < count; i++) {
233923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            CharSequence suggestion = mSuggestions.get(i);
234923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (suggestion == null) continue;
235923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            paint.setColor(mColorNormal);
236923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (mHaveMinimalSuggestion
237923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    && ((i == 1 && !typedWordValid) || (i == 0 && typedWordValid))) {
238923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                paint.setTypeface(Typeface.DEFAULT_BOLD);
239923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                paint.setColor(mColorRecommended);
240923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            } else if (i != 0) {
241923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                paint.setColor(mColorOther);
242923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
243923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            final int wordWidth;
244923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (mWordWidth[i] != 0) {
245923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                wordWidth = mWordWidth[i];
246923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            } else {
247923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                float textWidth =  paint.measureText(suggestion, 0, suggestion.length());
2486a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani                wordWidth = Math.max(mMinTouchableWidth, (int) textWidth + X_GAP * 2);
249923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                mWordWidth[i] = wordWidth;
250923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
251923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
252923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mWordX[i] = x;
253923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
2546ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani            if (touchX + scrollX >= x && touchX + scrollX < x + wordWidth && !scrolled &&
2556ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani                    touchX != OUT_OF_BOUNDS) {
25666a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani                if (canvas != null && !mShowingAddToDictionary) {
257923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    canvas.translate(x, 0);
258923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    mSelectionHighlight.setBounds(0, bgPadding.top, wordWidth, height);
259923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    mSelectionHighlight.draw(canvas);
260923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    canvas.translate(-x, 0);
261923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    showPreview(i, null);
262923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                }
263923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                mSelectedString = suggestion;
264923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                mSelectedIndex = i;
265923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
266923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
267923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (canvas != null) {
2686a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani                canvas.drawText(suggestion, 0, suggestion.length(), x + wordWidth / 2, y, paint);
269923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                paint.setColor(mColorOther);
270923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                canvas.translate(x + wordWidth, 0);
27166a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani                // Draw a divider unless it's after the hint
27266a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani                if (!(mShowingAddToDictionary && i == 1)) {
27366a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani                    mDivider.draw(canvas);
27466a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani                }
275923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                canvas.translate(-x - wordWidth, 0);
276923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
277923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            paint.setTypeface(Typeface.DEFAULT);
278923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            x += wordWidth;
279923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
280923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mTotalWidth = x;
2817a722cbfc8bbb8a7b260895266a0fd3a9baf1994Amith Yamasani        if (mTargetScrollX != scrollX) {
282923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            scrollToTarget();
283923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
284923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
285923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
286923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void scrollToTarget() {
2877a722cbfc8bbb8a7b260895266a0fd3a9baf1994Amith Yamasani        int scrollX = getScrollX();
2887a722cbfc8bbb8a7b260895266a0fd3a9baf1994Amith Yamasani        if (mTargetScrollX > scrollX) {
2897a722cbfc8bbb8a7b260895266a0fd3a9baf1994Amith Yamasani            scrollX += SCROLL_PIXELS;
2907a722cbfc8bbb8a7b260895266a0fd3a9baf1994Amith Yamasani            if (scrollX >= mTargetScrollX) {
2917a722cbfc8bbb8a7b260895266a0fd3a9baf1994Amith Yamasani                scrollX = mTargetScrollX;
2927a722cbfc8bbb8a7b260895266a0fd3a9baf1994Amith Yamasani                scrollTo(scrollX, getScrollY());
293923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                requestLayout();
2947a722cbfc8bbb8a7b260895266a0fd3a9baf1994Amith Yamasani            } else {
2957a722cbfc8bbb8a7b260895266a0fd3a9baf1994Amith Yamasani                scrollTo(scrollX, getScrollY());
296923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
297923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        } else {
2987a722cbfc8bbb8a7b260895266a0fd3a9baf1994Amith Yamasani            scrollX -= SCROLL_PIXELS;
2997a722cbfc8bbb8a7b260895266a0fd3a9baf1994Amith Yamasani            if (scrollX <= mTargetScrollX) {
3007a722cbfc8bbb8a7b260895266a0fd3a9baf1994Amith Yamasani                scrollX = mTargetScrollX;
3017a722cbfc8bbb8a7b260895266a0fd3a9baf1994Amith Yamasani                scrollTo(scrollX, getScrollY());
302923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                requestLayout();
3037a722cbfc8bbb8a7b260895266a0fd3a9baf1994Amith Yamasani            } else {
3047a722cbfc8bbb8a7b260895266a0fd3a9baf1994Amith Yamasani                scrollTo(scrollX, getScrollY());
305923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
306923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
307923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        invalidate();
308923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
309923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
310923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void setSuggestions(List<CharSequence> suggestions, boolean completions,
311923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            boolean typedWordValid, boolean haveMinimalSuggestion) {
312923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        clear();
313923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (suggestions != null) {
314923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mSuggestions = new ArrayList<CharSequence>(suggestions);
315923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
316923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mShowingCompletions = completions;
317923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mTypedWordValid = typedWordValid;
3187a722cbfc8bbb8a7b260895266a0fd3a9baf1994Amith Yamasani        scrollTo(0, getScrollY());
319923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mTargetScrollX = 0;
320923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mHaveMinimalSuggestion = haveMinimalSuggestion;
321923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // Compute the total width
322923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        onDraw(null);
323923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        invalidate();
324923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        requestLayout();
325923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
326923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
32766a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani    public void showAddToDictionaryHint(CharSequence word) {
32866a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani        mWordToAddToDictionary = word;
32966a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani        ArrayList<CharSequence> suggestions = new ArrayList<CharSequence>();
33066a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani        suggestions.add(word);
33166a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani        suggestions.add(mAddToDictionaryHint);
33266a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani        setSuggestions(suggestions, false, false, false);
33366a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani        mShowingAddToDictionary = true;
33466a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani    }
33566a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani
3366558253160e2039c87f424bd814f402ecd31de3bKen Wakasa    public boolean dismissAddToDictionaryHint() {
3376558253160e2039c87f424bd814f402ecd31de3bKen Wakasa        if (!mShowingAddToDictionary) return false;
3386558253160e2039c87f424bd814f402ecd31de3bKen Wakasa        clear();
3396558253160e2039c87f424bd814f402ecd31de3bKen Wakasa        return true;
3406558253160e2039c87f424bd814f402ecd31de3bKen Wakasa    }
3416558253160e2039c87f424bd814f402ecd31de3bKen Wakasa
342923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void scrollPrev() {
343923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        int i = 0;
344923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        final int count = mSuggestions.size();
345923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        int firstItem = 0; // Actually just before the first item, if at the boundary
346923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        while (i < count) {
3477a722cbfc8bbb8a7b260895266a0fd3a9baf1994Amith Yamasani            if (mWordX[i] < getScrollX()
3487a722cbfc8bbb8a7b260895266a0fd3a9baf1994Amith Yamasani                    && mWordX[i] + mWordWidth[i] >= getScrollX() - 1) {
349923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                firstItem = i;
350923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                break;
351923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
352923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            i++;
353923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
354923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        int leftEdge = mWordX[firstItem] + mWordWidth[firstItem] - getWidth();
355923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (leftEdge < 0) leftEdge = 0;
356923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        updateScrollPosition(leftEdge);
357923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
358923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
359923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void scrollNext() {
360923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        int i = 0;
3617a722cbfc8bbb8a7b260895266a0fd3a9baf1994Amith Yamasani        int scrollX = getScrollX();
3627a722cbfc8bbb8a7b260895266a0fd3a9baf1994Amith Yamasani        int targetX = scrollX;
363923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        final int count = mSuggestions.size();
3647a722cbfc8bbb8a7b260895266a0fd3a9baf1994Amith Yamasani        int rightEdge = scrollX + getWidth();
365923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        while (i < count) {
366923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (mWordX[i] <= rightEdge &&
367923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    mWordX[i] + mWordWidth[i] >= rightEdge) {
368923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                targetX = Math.min(mWordX[i], mTotalWidth - getWidth());
369923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                break;
370923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
371923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            i++;
372923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
373923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        updateScrollPosition(targetX);
374923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
375923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
376923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void updateScrollPosition(int targetX) {
3777a722cbfc8bbb8a7b260895266a0fd3a9baf1994Amith Yamasani        if (targetX != getScrollX()) {
378923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            // TODO: Animate
379923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mTargetScrollX = targetX;
380923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            requestLayout();
381923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            invalidate();
382923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mScrolled = true;
383923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
384923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
385923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
386923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void clear() {
387923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mSuggestions = EMPTY_LIST;
388923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mTouchX = OUT_OF_BOUNDS;
389923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mSelectedString = null;
390923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mSelectedIndex = -1;
39166a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani        mShowingAddToDictionary = false;
392923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        invalidate();
393923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        Arrays.fill(mWordWidth, 0);
394923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        Arrays.fill(mWordX, 0);
395923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (mPreviewPopup.isShowing()) {
396923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mPreviewPopup.dismiss();
397923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
398923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
399923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
400923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    @Override
401923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public boolean onTouchEvent(MotionEvent me) {
402923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
403923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (mGestureDetector.onTouchEvent(me)) {
404923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            return true;
405923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
406923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
407923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        int action = me.getAction();
408923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        int x = (int) me.getX();
409923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        int y = (int) me.getY();
410923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mTouchX = x;
411923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
412923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        switch (action) {
413923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        case MotionEvent.ACTION_DOWN:
414923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mScrolled = false;
415923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            invalidate();
416923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            break;
417923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        case MotionEvent.ACTION_MOVE:
418923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (y <= 0) {
419923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                // Fling up!?
420923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                if (mSelectedString != null) {
421923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    if (!mShowingCompletions) {
422923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                        TextEntryState.acceptedSuggestion(mSuggestions.get(0),
423923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                                mSelectedString);
424923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    }
425923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    mService.pickSuggestionManually(mSelectedIndex, mSelectedString);
426923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    mSelectedString = null;
427923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    mSelectedIndex = -1;
428923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                }
429923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
430923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            invalidate();
431923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            break;
432923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        case MotionEvent.ACTION_UP:
433923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (!mScrolled) {
434923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                if (mSelectedString != null) {
43566a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani                    if (mShowingAddToDictionary) {
43666a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani                        longPressFirstWord();
43766a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani                        clear();
43866a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani                    } else {
43966a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani                        if (!mShowingCompletions) {
44066a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani                            TextEntryState.acceptedSuggestion(mSuggestions.get(0),
44166a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani                                    mSelectedString);
44266a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani                        }
44366a787b953d703201c6b827abbee74e8cd9bb063Amith Yamasani                        mService.pickSuggestionManually(mSelectedIndex, mSelectedString);
444923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    }
445923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                }
446923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
447923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mSelectedString = null;
448923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mSelectedIndex = -1;
449923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            removeHighlight();
4506ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani            hidePreview();
451923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            requestLayout();
452923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            break;
453923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
454923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        return true;
455923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
456923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
457923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    /**
458923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     * For flick through from keyboard, call this method with the x coordinate of the flick
459923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     * gesture.
460923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     * @param x
461923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     */
462923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void takeSuggestionAt(float x) {
463923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mTouchX = (int) x;
464923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // To detect candidate
465923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        onDraw(null);
466923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (mSelectedString != null) {
467923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (!mShowingCompletions) {
468923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                TextEntryState.acceptedSuggestion(mSuggestions.get(0), mSelectedString);
469923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
470923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            mService.pickSuggestionManually(mSelectedIndex, mSelectedString);
471923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
472923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        invalidate();
473923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_REMOVE_THROUGH_PREVIEW), 200);
474923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
475923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
4766ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani    private void hidePreview() {
4776ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani        mCurrentWordIndex = OUT_OF_BOUNDS;
4786ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani        if (mPreviewPopup.isShowing()) {
4796ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani            mHandler.sendMessageDelayed(mHandler
4806ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani                    .obtainMessage(MSG_REMOVE_PREVIEW), 60);
4816ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani        }
4826ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani    }
4836ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani
484923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void showPreview(int wordIndex, String altText) {
485923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        int oldWordIndex = mCurrentWordIndex;
486923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mCurrentWordIndex = wordIndex;
487923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        // If index changed or changing text
488923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (oldWordIndex != mCurrentWordIndex || altText != null) {
489923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            if (wordIndex == OUT_OF_BOUNDS) {
4906ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani                hidePreview();
491923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            } else {
492923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                CharSequence word = altText != null? altText : mSuggestions.get(wordIndex);
493923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                mPreviewText.setText(word);
494923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                mPreviewText.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
495923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                        MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
496923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                int wordWidth = (int) (mPaint.measureText(word, 0, word.length()) + X_GAP * 2);
497923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                final int popupWidth = wordWidth
498923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                        + mPreviewText.getPaddingLeft() + mPreviewText.getPaddingRight();
499923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                final int popupHeight = mPreviewText.getMeasuredHeight();
500923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                //mPreviewText.setVisibility(INVISIBLE);
5016a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani                mPopupPreviewX = mWordX[wordIndex] - mPreviewText.getPaddingLeft() - getScrollX()
5026a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani                        + (mWordWidth[wordIndex] - wordWidth) / 2;
503923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                mPopupPreviewY = - popupHeight;
504923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                mHandler.removeMessages(MSG_REMOVE_PREVIEW);
505923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                int [] offsetInWindow = new int[2];
506923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                getLocationInWindow(offsetInWindow);
507923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                if (mPreviewPopup.isShowing()) {
508923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    mPreviewPopup.update(mPopupPreviewX, mPopupPreviewY + offsetInWindow[1],
509923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                            popupWidth, popupHeight);
510923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                } else {
511923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    mPreviewPopup.setWidth(popupWidth);
512923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    mPreviewPopup.setHeight(popupHeight);
513923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                    mPreviewPopup.showAtLocation(this, Gravity.NO_GRAVITY, mPopupPreviewX,
514923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                            mPopupPreviewY + offsetInWindow[1]);
515923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                }
516923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project                mPreviewText.setVisibility(VISIBLE);
517923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            }
518923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
519923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
520923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
521923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void removeHighlight() {
522923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mTouchX = OUT_OF_BOUNDS;
523923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        invalidate();
524923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
525923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
526923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private void longPressFirstWord() {
527923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        CharSequence word = mSuggestions.get(0);
5286a6075caba3865383eeeb52cccc63a28e4ae5900Amith Yamasani        if (word.length() < 2) return;
529923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        if (mService.addWordToDictionary(word.toString())) {
530923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project            showPreview(0, getContext().getResources().getString(R.string.added_word, word));
531923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
532923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
5336ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani
5346ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani    @Override
5356ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani    public void onDetachedFromWindow() {
5366ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani        super.onDetachedFromWindow();
5376ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani        hidePreview();
5386ec55a1599c74150e82ea7e4371ec815f0d2df27Amith Yamasani    }
539923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project}
540