FileDocCategorySizeDatePackage
CandidateView.javaAPI DocAndroid 1.5 API17252Wed May 06 22:42:48 BST 2009com.android.inputmethod.latin

CandidateView

public class CandidateView extends android.view.View

Fields Summary
private static final int
OUT_OF_BOUNDS
private static final List
EMPTY_LIST
private LatinIME
mService
private List
mSuggestions
private boolean
mShowingCompletions
private CharSequence
mSelectedString
private int
mSelectedIndex
private int
mTouchX
private android.graphics.drawable.Drawable
mSelectionHighlight
private boolean
mTypedWordValid
private boolean
mHaveMinimalSuggestion
private android.graphics.Rect
mBgPadding
private android.widget.TextView
mPreviewText
private android.widget.PopupWindow
mPreviewPopup
private int
mCurrentWordIndex
private android.graphics.drawable.Drawable
mDivider
private static final int
MAX_SUGGESTIONS
private static final int
SCROLL_PIXELS
private static final int
MSG_REMOVE_PREVIEW
private static final int
MSG_REMOVE_THROUGH_PREVIEW
private int[]
mWordWidth
private int[]
mWordX
private int
mPopupPreviewX
private int
mPopupPreviewY
private static final int
X_GAP
private int
mColorNormal
private int
mColorRecommended
private int
mColorOther
private android.graphics.Paint
mPaint
private int
mDescent
private boolean
mScrolled
private int
mTargetScrollX
private int
mTotalWidth
private android.view.GestureDetector
mGestureDetector
android.os.Handler
mHandler
Constructors Summary
public CandidateView(android.content.Context context, android.util.AttributeSet attrs)
Construct a CandidateView for showing suggested words for completion.

param
context
param
attrs


                      
         
        super(context, attrs);
        mSelectionHighlight = context.getResources().getDrawable(
                com.android.internal.R.drawable.list_selector_background_pressed);

        LayoutInflater inflate =
            (LayoutInflater) context
                    .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        mPreviewPopup = new PopupWindow(context);
        mPreviewText = (TextView) inflate.inflate(R.layout.candidate_preview, null);
        mPreviewPopup.setWindowLayoutMode(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
        mPreviewPopup.setContentView(mPreviewText);
        mPreviewPopup.setBackgroundDrawable(null);
        mColorNormal = context.getResources().getColor(R.color.candidate_normal);
        mColorRecommended = context.getResources().getColor(R.color.candidate_recommended);
        mColorOther = context.getResources().getColor(R.color.candidate_other);
        mDivider = context.getResources().getDrawable(R.drawable.keyboard_suggest_strip_divider);

        mPaint = new Paint();
        mPaint.setColor(mColorNormal);
        mPaint.setAntiAlias(true);
        mPaint.setTextSize(mPreviewText.getTextSize());
        mPaint.setStrokeWidth(0);
        mDescent = (int) mPaint.descent();
        
        mGestureDetector = new GestureDetector(new GestureDetector.SimpleOnGestureListener() {
            @Override
            public void onLongPress(MotionEvent me) {
                if (mSuggestions.size() > 0) {
                    if (me.getX() + mScrollX < mWordWidth[0] && mScrollX < 10) {
                        longPressFirstWord();
                    }
                }
            }
            
            @Override
            public boolean onScroll(MotionEvent e1, MotionEvent e2,
                    float distanceX, float distanceY) {
                final int width = getWidth();
                mScrolled = true;
                mScrollX += (int) distanceX;
                if (mScrollX < 0) {
                    mScrollX = 0;
                }
                if (distanceX > 0 && mScrollX + width > mTotalWidth) {                    
                    mScrollX -= (int) distanceX;
                }
                mTargetScrollX = mScrollX;
                hidePreview();
                invalidate();
                return true;
            }
        });
        setHorizontalFadingEdgeEnabled(true);
        setWillNotDraw(false);
        setHorizontalScrollBarEnabled(false);
        setVerticalScrollBarEnabled(false);
        mScrollX = 0;
    
Methods Summary
public voidclear()

        mSuggestions = EMPTY_LIST;
        mTouchX = OUT_OF_BOUNDS;
        mSelectedString = null;
        mSelectedIndex = -1;
        invalidate();
        Arrays.fill(mWordWidth, 0);
        Arrays.fill(mWordX, 0);
        if (mPreviewPopup.isShowing()) {
            mPreviewPopup.dismiss();
        }
    
public intcomputeHorizontalScrollRange()

        return mTotalWidth;
    
private voidhidePreview()

        mCurrentWordIndex = OUT_OF_BOUNDS;
        if (mPreviewPopup.isShowing()) {
            mHandler.sendMessageDelayed(mHandler
                    .obtainMessage(MSG_REMOVE_PREVIEW), 60);
        }
    
private voidlongPressFirstWord()

        CharSequence word = mSuggestions.get(0);
        if (mService.addWordToDictionary(word.toString())) {
            showPreview(0, getContext().getResources().getString(R.string.added_word, word));
        }
    
public voidonDetachedFromWindow()

        super.onDetachedFromWindow();
        hidePreview();
    
protected voidonDraw(android.graphics.Canvas canvas)
If the canvas is null, then only touch calculations are performed to pick the target candidate.

        if (canvas != null) {
            super.onDraw(canvas);
        }
        mTotalWidth = 0;
        if (mSuggestions == null) return;
        
        final int height = getHeight();
        if (mBgPadding == null) {
            mBgPadding = new Rect(0, 0, 0, 0);
            if (getBackground() != null) {
                getBackground().getPadding(mBgPadding);
            }
            mDivider.setBounds(0, mBgPadding.top, mDivider.getIntrinsicWidth(), 
                    mDivider.getIntrinsicHeight());
        }
        int x = 0;
        final int count = mSuggestions.size(); 
        final int width = getWidth();
        final Rect bgPadding = mBgPadding;
        final Paint paint = mPaint;
        final int touchX = mTouchX;
        final int scrollX = mScrollX;
        final boolean scrolled = mScrolled;
        final boolean typedWordValid = mTypedWordValid;
        final int y = (int) (height + mPaint.getTextSize() - mDescent) / 2;

        for (int i = 0; i < count; i++) {
            CharSequence suggestion = mSuggestions.get(i);
            if (suggestion == null) continue;
            paint.setColor(mColorNormal);
            if (mHaveMinimalSuggestion 
                    && ((i == 1 && !typedWordValid) || (i == 0 && typedWordValid))) {
                paint.setTypeface(Typeface.DEFAULT_BOLD);
                paint.setColor(mColorRecommended);
            } else if (i != 0) {
                paint.setColor(mColorOther);
            }
            final int wordWidth;
            if (mWordWidth[i] != 0) {
                wordWidth = mWordWidth[i];
            } else {
                float textWidth =  paint.measureText(suggestion, 0, suggestion.length());
                wordWidth = (int) textWidth + X_GAP * 2;
                mWordWidth[i] = wordWidth;
            }

            mWordX[i] = x;

            if (touchX + scrollX >= x && touchX + scrollX < x + wordWidth && !scrolled &&
                    touchX != OUT_OF_BOUNDS) {
                if (canvas != null) {
                    canvas.translate(x, 0);
                    mSelectionHighlight.setBounds(0, bgPadding.top, wordWidth, height);
                    mSelectionHighlight.draw(canvas);
                    canvas.translate(-x, 0);
                    showPreview(i, null);
                }
                mSelectedString = suggestion;
                mSelectedIndex = i;
            }

            if (canvas != null) {
                canvas.drawText(suggestion, 0, suggestion.length(), x + X_GAP, y, paint);
                paint.setColor(mColorOther);
                canvas.translate(x + wordWidth, 0);
                mDivider.draw(canvas);
                canvas.translate(-x - wordWidth, 0);
            }
            paint.setTypeface(Typeface.DEFAULT);
            x += wordWidth;
        }
        mTotalWidth = x;
        if (mTargetScrollX != mScrollX) {
            scrollToTarget();
        }
    
public booleanonTouchEvent(android.view.MotionEvent me)


        if (mGestureDetector.onTouchEvent(me)) {
            return true;
        }

        int action = me.getAction();
        int x = (int) me.getX();
        int y = (int) me.getY();
        mTouchX = x;

        switch (action) {
        case MotionEvent.ACTION_DOWN:
            mScrolled = false;
            invalidate();
            break;
        case MotionEvent.ACTION_MOVE:
            if (y <= 0) {
                // Fling up!?
                if (mSelectedString != null) {
                    if (!mShowingCompletions) {
                        TextEntryState.acceptedSuggestion(mSuggestions.get(0),
                                mSelectedString);
                    }
                    mService.pickSuggestionManually(mSelectedIndex, mSelectedString);
                    mSelectedString = null;
                    mSelectedIndex = -1;
                }
            }
            invalidate();
            break;
        case MotionEvent.ACTION_UP:
            if (!mScrolled) {
                if (mSelectedString != null) {
                    if (!mShowingCompletions) {
                        TextEntryState.acceptedSuggestion(mSuggestions.get(0),
                                mSelectedString);
                    }
                    mService.pickSuggestionManually(mSelectedIndex, mSelectedString);
                }
            }
            mSelectedString = null;
            mSelectedIndex = -1;
            removeHighlight();
            hidePreview();
            requestLayout();
            break;
        }
        return true;
    
private voidremoveHighlight()

        mTouchX = OUT_OF_BOUNDS;
        invalidate();
    
public voidscrollNext()

        int i = 0;
        int targetX = mScrollX;
        final int count = mSuggestions.size();
        int rightEdge = mScrollX + getWidth();
        while (i < count) {
            if (mWordX[i] <= rightEdge &&
                    mWordX[i] + mWordWidth[i] >= rightEdge) {
                targetX = Math.min(mWordX[i], mTotalWidth - getWidth());
                break;
            }
            i++;
        }
        updateScrollPosition(targetX);
    
public voidscrollPrev()

        int i = 0;
        final int count = mSuggestions.size();
        int firstItem = 0; // Actually just before the first item, if at the boundary
        while (i < count) {
            if (mWordX[i] < mScrollX 
                    && mWordX[i] + mWordWidth[i] >= mScrollX - 1) {
                firstItem = i;
                break;
            }
            i++;
        }
        int leftEdge = mWordX[firstItem] + mWordWidth[firstItem] - getWidth();
        if (leftEdge < 0) leftEdge = 0;
        updateScrollPosition(leftEdge);
    
private voidscrollToTarget()

        if (mTargetScrollX > mScrollX) {
            mScrollX += SCROLL_PIXELS;
            if (mScrollX >= mTargetScrollX) {
                mScrollX = mTargetScrollX;
                requestLayout();
            }
        } else {
            mScrollX -= SCROLL_PIXELS;
            if (mScrollX <= mTargetScrollX) {
                mScrollX = mTargetScrollX;
                requestLayout();
            }
        }
        invalidate();
    
public voidsetService(LatinIME listener)
A connection back to the service to communicate with the text field

param
listener

        mService = listener;
    
public voidsetSuggestions(java.util.List suggestions, boolean completions, boolean typedWordValid, boolean haveMinimalSuggestion)

        clear();
        if (suggestions != null) {
            mSuggestions = new ArrayList<CharSequence>(suggestions);
        }
        mShowingCompletions = completions;
        mTypedWordValid = typedWordValid;
        mScrollX = 0;
        mTargetScrollX = 0;
        mHaveMinimalSuggestion = haveMinimalSuggestion;
        // Compute the total width
        onDraw(null);
        invalidate();
        requestLayout();
    
private voidshowPreview(int wordIndex, java.lang.String altText)

        int oldWordIndex = mCurrentWordIndex;
        mCurrentWordIndex = wordIndex;
        // If index changed or changing text
        if (oldWordIndex != mCurrentWordIndex || altText != null) {
            if (wordIndex == OUT_OF_BOUNDS) {
                hidePreview();
            } else {
                CharSequence word = altText != null? altText : mSuggestions.get(wordIndex);
                mPreviewText.setText(word);
                mPreviewText.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), 
                        MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
                int wordWidth = (int) (mPaint.measureText(word, 0, word.length()) + X_GAP * 2);
                final int popupWidth = wordWidth
                        + mPreviewText.getPaddingLeft() + mPreviewText.getPaddingRight();
                final int popupHeight = mPreviewText.getMeasuredHeight();
                //mPreviewText.setVisibility(INVISIBLE);
                mPopupPreviewX = mWordX[wordIndex] - mPreviewText.getPaddingLeft() - mScrollX;
                mPopupPreviewY = - popupHeight;
                mHandler.removeMessages(MSG_REMOVE_PREVIEW);
                int [] offsetInWindow = new int[2];
                getLocationInWindow(offsetInWindow);
                if (mPreviewPopup.isShowing()) {
                    mPreviewPopup.update(mPopupPreviewX, mPopupPreviewY + offsetInWindow[1], 
                            popupWidth, popupHeight);
                } else {
                    mPreviewPopup.setWidth(popupWidth);
                    mPreviewPopup.setHeight(popupHeight);
                    mPreviewPopup.showAtLocation(this, Gravity.NO_GRAVITY, mPopupPreviewX, 
                            mPopupPreviewY + offsetInWindow[1]);
                }
                mPreviewText.setVisibility(VISIBLE);
            }
        }
    
public voidtakeSuggestionAt(float x)
For flick through from keyboard, call this method with the x coordinate of the flick gesture.

param
x

        mTouchX = (int) x;
        // To detect candidate
        onDraw(null);
        if (mSelectedString != null) {
            if (!mShowingCompletions) {
                TextEntryState.acceptedSuggestion(mSuggestions.get(0), mSelectedString);
            }
            mService.pickSuggestionManually(mSelectedIndex, mSelectedString);
        }
        invalidate();
        mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_REMOVE_THROUGH_PREVIEW), 200);
    
private voidupdateScrollPosition(int targetX)

        if (targetX != mScrollX) {
            // TODO: Animate
            mTargetScrollX = targetX;
            requestLayout();
            invalidate();
            mScrolled = true;
        }