17898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project/*
27898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project * Copyright (C) 2009 The Android Open Source Project
37898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project *
47898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
57898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project * you may not use this file except in compliance with the License.
67898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project * You may obtain a copy of the License at
77898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project *
87898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
97898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project *
107898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project * Unless required by applicable law or agreed to in writing, software
117898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
127898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
137898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project * See the License for the specific language governing permissions and
147898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project * limitations under the License.
157898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project */
167898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project
177898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Projectpackage com.android.inputmethod.pinyin;
187898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project
197898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Projectimport android.content.Context;
207898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Projectimport android.graphics.Canvas;
217898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Projectimport android.graphics.Paint;
227898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Projectimport android.graphics.Rect;
237898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Projectimport android.graphics.Paint.FontMetricsInt;
247898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Projectimport android.graphics.drawable.ColorDrawable;
257898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Projectimport android.graphics.drawable.Drawable;
267898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Projectimport android.os.Handler;
277898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Projectimport android.view.Gravity;
287898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Projectimport android.view.View;
297898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Projectimport android.view.View.MeasureSpec;
307898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Projectimport android.widget.PopupWindow;
317898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project
327898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project/**
337898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project * Subclass of PopupWindow used as the feedback when user presses on a soft key
347898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project * or a candidate.
357898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project */
367898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Projectpublic class BalloonHint extends PopupWindow {
377898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project    /**
387898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project     * Delayed time to show the balloon hint.
397898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project     */
407898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project    public static final int TIME_DELAY_SHOW = 0;
417898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project
427898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project    /**
437898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project     * Delayed time to dismiss the balloon hint.
447898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project     */
457898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project    public static final int TIME_DELAY_DISMISS = 200;
467898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project
477898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project    /**
487898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project     * The padding information of the balloon. Because PopupWindow's background
497898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project     * can not be changed unless it is dismissed and shown again, we set the
507898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project     * real background drawable to the content view, and make the PopupWindow's
517898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project     * background transparent. So actually this padding information is for the
527898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project     * content view.
537898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project     */
547898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project    private Rect mPaddingRect = new Rect();
557898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project
567898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project    /**
577898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project     * The context used to create this balloon hint object.
587898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project     */
597898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project    private Context mContext;
607898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project
617898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project    /**
627898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project     * Parent used to show the balloon window.
637898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project     */
647898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project    private View mParent;
657898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project
667898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project    /**
677898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project     * The content view of the balloon.
687898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project     */
697898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project    BalloonView mBalloonView;
707898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project
717898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project    /**
727898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project     * The measuring specification used to determine its size. Key-press
737898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project     * balloons and candidates balloons have different measuring specifications.
747898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project     */
757898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project    private int mMeasureSpecMode;
767898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project
777898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project    /**
787898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project     * Used to indicate whether the balloon needs to be dismissed forcibly.
797898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project     */
807898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project    private boolean mForceDismiss;
817898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project
827898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project    /**
837898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project     * Timer used to show/dismiss the balloon window with some time delay.
847898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project     */
857898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project    private BalloonTimer mBalloonTimer;
867898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project
877898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project    private int mParentLocationInWindow[] = new int[2];
887898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project
897898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project    public BalloonHint(Context context, View parent, int measureSpecMode) {
907898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        super(context);
917898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        mParent = parent;
927898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        mMeasureSpecMode = measureSpecMode;
937898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project
947898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED);
957898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        setTouchable(false);
967898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        setBackgroundDrawable(new ColorDrawable(0));
977898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project
987898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        mBalloonView = new BalloonView(context);
997898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        mBalloonView.setClickable(false);
1007898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        setContentView(mBalloonView);
1017898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project
1027898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        mBalloonTimer = new BalloonTimer();
1037898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project    }
1047898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project
1057898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project    public Context getContext() {
1067898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        return mContext;
1077898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project    }
1087898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project
1097898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project    public Rect getPadding() {
1107898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        return mPaddingRect;
1117898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project    }
1127898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project
1137898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project    public void setBalloonBackground(Drawable drawable) {
1147898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        // We usually pick up a background from a soft keyboard template,
1157898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        // and the object may has been set to this balloon before.
1167898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        if (mBalloonView.getBackground() == drawable) return;
1177898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        mBalloonView.setBackgroundDrawable(drawable);
1187898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project
1197898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        if (null != drawable) {
1207898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project            drawable.getPadding(mPaddingRect);
1217898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        } else {
1227898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project            mPaddingRect.set(0, 0, 0, 0);
1237898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        }
1247898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project    }
1257898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project
1267898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project    /**
1277898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project     * Set configurations to show text label in this balloon.
1287898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project     *
1297898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project     * @param label The text label to show in the balloon.
1307898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project     * @param textSize The text size used to show label.
1317898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project     * @param textBold Used to indicate whether the label should be bold.
1327898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project     * @param textColor The text color used to show label.
1337898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project     * @param width The desired width of the balloon. The real width is
1347898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project     *        determined by the desired width and balloon's measuring
1357898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project     *        specification.
1367898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project     * @param height The desired width of the balloon. The real width is
1377898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project     *        determined by the desired width and balloon's measuring
1387898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project     *        specification.
1397898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project     */
1407898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project    public void setBalloonConfig(String label, float textSize,
1417898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project            boolean textBold, int textColor, int width, int height) {
1427898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        mBalloonView.setTextConfig(label, textSize, textBold, textColor);
1437898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        setBalloonSize(width, height);
1447898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project    }
1457898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project
1467898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project    /**
1477898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project     * Set configurations to show text label in this balloon.
1487898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project     *
1497898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project     * @param icon The icon used to shown in this balloon.
1507898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project     * @param width The desired width of the balloon. The real width is
1517898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project     *        determined by the desired width and balloon's measuring
1527898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project     *        specification.
1537898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project     * @param height The desired width of the balloon. The real width is
1547898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project     *        determined by the desired width and balloon's measuring
1557898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project     *        specification.
1567898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project     */
1577898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project    public void setBalloonConfig(Drawable icon, int width, int height) {
1587898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        mBalloonView.setIcon(icon);
1597898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        setBalloonSize(width, height);
1607898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project    }
1617898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project
1627898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project
1637898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project    public boolean needForceDismiss() {
1647898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        return mForceDismiss;
1657898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project    }
1667898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project
1677898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project    public int getPaddingLeft() {
1687898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        return mPaddingRect.left;
1697898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project    }
1707898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project
1717898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project    public int getPaddingTop() {
1727898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        return mPaddingRect.top;
1737898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project    }
1747898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project
1757898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project    public int getPaddingRight() {
1767898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        return mPaddingRect.right;
1777898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project    }
1787898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project
1797898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project    public int getPaddingBottom() {
1807898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        return mPaddingRect.bottom;
1817898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project    }
1827898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project
1837898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project    public void delayedShow(long delay, int locationInParent[]) {
1847898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        if (mBalloonTimer.isPending()) {
1857898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project            mBalloonTimer.removeTimer();
1867898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        }
1877898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        if (delay <= 0) {
1887898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project            mParent.getLocationInWindow(mParentLocationInWindow);
1897898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project            showAtLocation(mParent, Gravity.LEFT | Gravity.TOP,
1907898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project                    locationInParent[0], locationInParent[1]
1917898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project                            + mParentLocationInWindow[1]);
1927898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        } else {
1937898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project            mBalloonTimer.startTimer(delay, BalloonTimer.ACTION_SHOW,
1947898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project                    locationInParent, -1, -1);
1957898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        }
1967898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project    }
1977898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project
1987898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project    public void delayedUpdate(long delay, int locationInParent[],
1997898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project            int width, int height) {
2007898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        mBalloonView.invalidate();
2017898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        if (mBalloonTimer.isPending()) {
2027898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project            mBalloonTimer.removeTimer();
2037898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        }
2047898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        if (delay <= 0) {
2057898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project            mParent.getLocationInWindow(mParentLocationInWindow);
2067898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project            update(locationInParent[0], locationInParent[1]
2077898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project                    + mParentLocationInWindow[1], width, height);
2087898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        } else {
2097898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project            mBalloonTimer.startTimer(delay, BalloonTimer.ACTION_UPDATE,
2107898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project                    locationInParent, width, height);
2117898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        }
2127898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project    }
2137898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project
2147898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project    public void delayedDismiss(long delay) {
2157898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        if (mBalloonTimer.isPending()) {
2167898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project            mBalloonTimer.removeTimer();
2177898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project            int pendingAction = mBalloonTimer.getAction();
2187898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project            if (0 != delay && BalloonTimer.ACTION_HIDE != pendingAction) {
2197898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project                mBalloonTimer.run();
2207898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project            }
2217898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        }
2227898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        if (delay <= 0) {
2237898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project            dismiss();
2247898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        } else {
2257898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project            mBalloonTimer.startTimer(delay, BalloonTimer.ACTION_HIDE, null, -1,
2267898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project                    -1);
2277898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        }
2287898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project    }
2297898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project
2307898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project    public void removeTimer() {
2317898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        if (mBalloonTimer.isPending()) {
2327898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project            mBalloonTimer.removeTimer();
2337898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        }
2347898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project    }
2357898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project
2367898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project    private void setBalloonSize(int width, int height) {
2377898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        int widthMeasureSpec = MeasureSpec.makeMeasureSpec(width,
2387898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project                mMeasureSpecMode);
2397898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        int heightMeasureSpec = MeasureSpec.makeMeasureSpec(height,
2407898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project                mMeasureSpecMode);
2417898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        mBalloonView.measure(widthMeasureSpec, heightMeasureSpec);
2427898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project
2437898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        int oldWidth = getWidth();
2447898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        int oldHeight = getHeight();
2457898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        int newWidth = mBalloonView.getMeasuredWidth() + getPaddingLeft()
2467898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project                + getPaddingRight();
2477898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        int newHeight = mBalloonView.getMeasuredHeight() + getPaddingTop()
2487898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project                + getPaddingBottom();
2497898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        setWidth(newWidth);
2507898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        setHeight(newHeight);
2517898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project
2527898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        // If update() is called to update both size and position, the system
2537898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        // will first MOVE the PopupWindow to the new position, and then
2547898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        // perform a size-updating operation, so there will be a flash in
2557898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        // PopupWindow if user presses a key and moves finger to next one whose
2567898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        // size is different.
2577898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        // PopupWindow will handle the updating issue in one go in the future,
2587898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        // but before that, if we find the size is changed, a mandatory dismiss
2597898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        // operation is required. In our UI design, normal QWERTY keys' width
2607898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        // can be different in 1-pixel, and we do not dismiss the balloon when
2617898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        // user move between QWERTY keys.
2627898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        mForceDismiss = false;
2637898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        if (isShowing()) {
2647898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project            mForceDismiss = oldWidth - newWidth > 1 || newWidth - oldWidth > 1;
2657898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        }
2667898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project    }
2677898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project
2687898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project
2697898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project    private class BalloonTimer extends Handler implements Runnable {
2707898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        public static final int ACTION_SHOW = 1;
2717898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        public static final int ACTION_HIDE = 2;
2727898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        public static final int ACTION_UPDATE = 3;
2737898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project
2747898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        /**
2757898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project         * The pending action.
2767898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project         */
2777898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        private int mAction;
2787898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project
2797898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        private int mPositionInParent[] = new int[2];
2807898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        private int mWidth;
2817898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        private int mHeight;
2827898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project
2837898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        private boolean mTimerPending = false;
2847898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project
2857898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        public void startTimer(long time, int action, int positionInParent[],
2867898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project                int width, int height) {
2877898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project            mAction = action;
2887898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project            if (ACTION_HIDE != action) {
2897898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project                mPositionInParent[0] = positionInParent[0];
2907898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project                mPositionInParent[1] = positionInParent[1];
2917898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project            }
2927898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project            mWidth = width;
2937898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project            mHeight = height;
2947898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project            postDelayed(this, time);
2957898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project            mTimerPending = true;
2967898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        }
2977898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project
2987898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        public boolean isPending() {
2997898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project            return mTimerPending;
3007898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        }
3017898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project
3027898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        public boolean removeTimer() {
3037898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project            if (mTimerPending) {
3047898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project                mTimerPending = false;
3057898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project                removeCallbacks(this);
3067898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project                return true;
3077898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project            }
3087898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project
3097898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project            return false;
3107898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        }
3117898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project
3127898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        public int getAction() {
3137898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project            return mAction;
3147898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        }
3157898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project
3167898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        public void run() {
3177898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project            switch (mAction) {
3187898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project            case ACTION_SHOW:
3197898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project                mParent.getLocationInWindow(mParentLocationInWindow);
3207898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project                showAtLocation(mParent, Gravity.LEFT | Gravity.TOP,
3217898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project                        mPositionInParent[0], mPositionInParent[1]
3227898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project                                + mParentLocationInWindow[1]);
3237898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project                break;
3247898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project            case ACTION_HIDE:
3257898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project                dismiss();
3267898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project                break;
3277898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project            case ACTION_UPDATE:
3287898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project                mParent.getLocationInWindow(mParentLocationInWindow);
3297898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project                update(mPositionInParent[0], mPositionInParent[1]
3307898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project                        + mParentLocationInWindow[1], mWidth, mHeight);
3317898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project            }
3327898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project            mTimerPending = false;
3337898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        }
3347898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project    }
3357898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project
3367898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project    private class BalloonView extends View {
3377898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        /**
3387898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project         * Suspension points used to display long items.
3397898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project         */
3407898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        private static final String SUSPENSION_POINTS = "...";
3417898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project
3427898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        /**
3437898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project         * The icon to be shown. If it is not null, {@link #mLabel} will be
3447898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project         * ignored.
3457898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project         */
3467898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        private Drawable mIcon;
3477898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project
3487898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        /**
3497898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project         * The label to be shown. It is enabled only if {@link #mIcon} is null.
3507898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project         */
3517898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        private String mLabel;
3527898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project
3537898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        private int mLabeColor = 0xff000000;
3547898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        private Paint mPaintLabel;
3557898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        private FontMetricsInt mFmi;
3567898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project
3577898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        /**
3587898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project         * The width to show suspension points.
3597898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project         */
3607898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        private float mSuspensionPointsWidth;
3617898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project
3627898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project
3637898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        public BalloonView(Context context) {
3647898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project            super(context);
3657898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project            mPaintLabel = new Paint();
3667898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project            mPaintLabel.setColor(mLabeColor);
3677898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project            mPaintLabel.setAntiAlias(true);
3687898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project            mPaintLabel.setFakeBoldText(true);
3697898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project            mFmi = mPaintLabel.getFontMetricsInt();
3707898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        }
3717898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project
3727898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        public void setIcon(Drawable icon) {
3737898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project            mIcon = icon;
3747898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        }
3757898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project
3767898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        public void setTextConfig(String label, float fontSize,
3777898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project                boolean textBold, int textColor) {
3787898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project            // Icon should be cleared so that the label will be enabled.
3797898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project            mIcon = null;
3807898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project            mLabel = label;
3817898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project            mPaintLabel.setTextSize(fontSize);
3827898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project            mPaintLabel.setFakeBoldText(textBold);
3837898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project            mPaintLabel.setColor(textColor);
3847898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project            mFmi = mPaintLabel.getFontMetricsInt();
3857898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project            mSuspensionPointsWidth = mPaintLabel.measureText(SUSPENSION_POINTS);
3867898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        }
3877898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project
3887898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        @Override
3897898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
3907898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project            final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
3917898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project            final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
3927898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project            final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
3937898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project            final int heightSize = MeasureSpec.getSize(heightMeasureSpec);
3947898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project
3957898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project            if (widthMode == MeasureSpec.EXACTLY) {
3967898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project                setMeasuredDimension(widthSize, heightSize);
3977898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project                return;
3987898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project            }
3997898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project
4007898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project            int measuredWidth = mPaddingLeft + mPaddingRight;
4017898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project            int measuredHeight = mPaddingTop + mPaddingBottom;
4027898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project            if (null != mIcon) {
4037898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project                measuredWidth += mIcon.getIntrinsicWidth();
4047898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project                measuredHeight += mIcon.getIntrinsicHeight();
4057898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project            } else if (null != mLabel) {
4067898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project                measuredWidth += (int) (mPaintLabel.measureText(mLabel));
4077898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project                measuredHeight += mFmi.bottom - mFmi.top;
4087898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project            }
4097898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project            if (widthSize > measuredWidth || widthMode == MeasureSpec.AT_MOST) {
4107898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project                measuredWidth = widthSize;
4117898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project            }
4127898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project
4137898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project            if (heightSize > measuredHeight
4147898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project                    || heightMode == MeasureSpec.AT_MOST) {
4157898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project                measuredHeight = heightSize;
4167898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project            }
4177898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project
4187898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project            int maxWidth = Environment.getInstance().getScreenWidth() -
4197898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project                    mPaddingLeft - mPaddingRight;
4207898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project            if (measuredWidth > maxWidth) {
4217898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project                measuredWidth = maxWidth;
4227898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project            }
4237898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project            setMeasuredDimension(measuredWidth, measuredHeight);
4247898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        }
4257898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project
4267898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        @Override
4277898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        protected void onDraw(Canvas canvas) {
4287898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project            int width = getWidth();
4297898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project            int height = getHeight();
4307898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project            if (null != mIcon) {
4317898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project                int marginLeft = (width - mIcon.getIntrinsicWidth()) / 2;
4327898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project                int marginRight = width - mIcon.getIntrinsicWidth()
4337898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project                        - marginLeft;
4347898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project                int marginTop = (height - mIcon.getIntrinsicHeight()) / 2;
4357898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project                int marginBottom = height - mIcon.getIntrinsicHeight()
4367898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project                        - marginTop;
4377898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project                mIcon.setBounds(marginLeft, marginTop, width - marginRight,
4387898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project                        height - marginBottom);
4397898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project                mIcon.draw(canvas);
4407898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project            } else if (null != mLabel) {
4417898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project                float labelMeasuredWidth = mPaintLabel.measureText(mLabel);
4427898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project                float x = mPaddingLeft;
4437898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project                x += (width - labelMeasuredWidth - mPaddingLeft - mPaddingRight) / 2.0f;
4447898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project                String labelToDraw = mLabel;
4457898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project                if (x < mPaddingLeft) {
4467898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project                    x = mPaddingLeft;
4477898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project                    labelToDraw = getLimitedLabelForDrawing(mLabel,
4487898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project                            width - mPaddingLeft - mPaddingRight);
4497898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project                }
4507898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project
4517898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project                int fontHeight = mFmi.bottom - mFmi.top;
4527898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project                float marginY = (height - fontHeight) / 2.0f;
4537898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project                float y = marginY - mFmi.top;
4547898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project                canvas.drawText(labelToDraw, x, y, mPaintLabel);
4557898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project            }
4567898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        }
4577898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project
4587898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        private String getLimitedLabelForDrawing(String rawLabel,
4597898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project                float widthToDraw) {
4607898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project            int subLen = rawLabel.length();
4617898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project            if (subLen <= 1) return rawLabel;
4627898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project            do {
4637898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project                subLen--;
4647898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project                float width = mPaintLabel.measureText(rawLabel, 0, subLen);
4657898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project                if (width + mSuspensionPointsWidth <= widthToDraw || 1 >= subLen) {
4667898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project                    return rawLabel.substring(0, subLen) +
4677898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project                            SUSPENSION_POINTS;
4687898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project                }
4697898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project            } while (true);
4707898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project        }
4717898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project    }
4727898d76cc005bbe1c5893a9f57439561e0771ccThe Android Open Source Project}
473