12e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet/*
22e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet * Copyright (C) 2007 The Android Open Source Project
32e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet *
42e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet * Licensed under the Apache License, Version 2.0 (the "License");
52e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet * you may not use this file except in compliance with the License.
62e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet * You may obtain a copy of the License at
72e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet *
82e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet *      http://www.apache.org/licenses/LICENSE-2.0
92e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet *
102e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet * Unless required by applicable law or agreed to in writing, software
112e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet * distributed under the License is distributed on an "AS IS" BASIS,
122e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
132e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet * See the License for the specific language governing permissions and
142e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet * limitations under the License.
152e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet */
162e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet
172e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohetpackage com.android.tests.libwithcustom;
182e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet
192e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet// Need the following import to get access to the app resources, since this
202e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet// class is in a sub-package.
212e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohetimport android.content.Context;
222e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohetimport android.content.res.TypedArray;
232e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohetimport android.graphics.Canvas;
242e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohetimport android.graphics.Paint;
252e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohetimport android.util.AttributeSet;
262e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohetimport android.view.View;
272e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet
282e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet
292e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet/**
302e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet * Example of how to write a custom subclass of View. LabelView
312e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet * is used to draw simple text views. Note that it does not handle
322e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet * styled text or right-to-left writing systems.
332e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet *
342e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet */
352e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohetpublic class LabelView extends View {
362e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet    private Paint mTextPaint;
372e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet    private String mText;
382e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet    private int mAscent;
392e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet
402e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet    /**
412e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet     * Constructor.  This version is only needed if you will be instantiating
422e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet     * the object manually (not from a layout XML file).
432e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet     * @param context
442e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet     */
452e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet    public LabelView(Context context) {
462e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet        super(context);
472e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet        initLabelView();
482e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet    }
492e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet
502e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet    /**
512e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet     * Construct object, initializing with any attributes we understand from a
522e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet     * layout file. These attributes are defined in
532e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet     * SDK/assets/res/any/classes.xml.
542e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet     *
552e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet     * @see android.view.View#View(android.content.Context, android.util.AttributeSet)
562e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet     */
572e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet    public LabelView(Context context, AttributeSet attrs) {
582e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet        super(context, attrs);
592e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet        initLabelView();
602e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet
612e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet
622e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet        TypedArray a = context.obtainStyledAttributes(attrs,
632e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet                R.styleable.LabelView);
642e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet
652e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet        CharSequence s = a.getString(R.styleable.LabelView_text);
662e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet        if (s != null) {
672e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet            setText(s.toString());
682e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet        }
692e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet
702e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet        // Retrieve the color(s) to be used for this view and apply them.
712e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet        // Note, if you only care about supporting a single color, that you
722e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet        // can instead call a.getColor() and pass that to setTextColor().
732e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet        setTextColor(a.getColor(R.styleable.LabelView_textColor, 0xFF000000));
742e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet
752e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet        int textSize = a.getDimensionPixelOffset(R.styleable.LabelView_textSize, 0);
762e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet        if (textSize > 0) {
772e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet            setTextSize(textSize);
782e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet        }
792e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet
802e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet        a.recycle();
812e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet    }
822e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet
832e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet    private final void initLabelView() {
842e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet        mTextPaint = new Paint();
852e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet        mTextPaint.setAntiAlias(true);
862e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet        // Must manually scale the desired text size to match screen density
872e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet        mTextPaint.setTextSize(16 * getResources().getDisplayMetrics().density);
882e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet        mTextPaint.setColor(0xFF000000);
892e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet        setPadding(3, 3, 3, 3);
902e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet    }
912e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet
922e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet    /**
932e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet     * Sets the text to display in this label
942e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet     * @param text The text to display. This will be drawn as one line.
952e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet     */
962e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet    public void setText(String text) {
972e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet        mText = text;
982e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet        requestLayout();
992e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet        invalidate();
1002e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet    }
1012e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet
1022e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet    /**
1032e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet     * Sets the text size for this label
1042e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet     * @param size Font size
1052e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet     */
1062e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet    public void setTextSize(int size) {
1072e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet        // This text size has been pre-scaled by the getDimensionPixelOffset method
1082e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet        mTextPaint.setTextSize(size);
1092e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet        requestLayout();
1102e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet        invalidate();
1112e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet    }
1122e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet
1132e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet    /**
1142e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet     * Sets the text color for this label.
1152e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet     * @param color ARGB value for the text
1162e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet     */
1172e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet    public void setTextColor(int color) {
1182e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet        mTextPaint.setColor(color);
1192e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet        invalidate();
1202e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet    }
1212e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet
1222e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet    /**
1232e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet     * @see android.view.View#measure(int, int)
1242e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet     */
1252e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet    @Override
1262e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
1272e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet        setMeasuredDimension(measureWidth(widthMeasureSpec),
1282e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet                measureHeight(heightMeasureSpec));
1292e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet    }
1302e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet
1312e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet    /**
1322e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet     * Determines the width of this view
1332e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet     * @param measureSpec A measureSpec packed into an int
1342e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet     * @return The width of the view, honoring constraints from measureSpec
1352e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet     */
1362e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet    private int measureWidth(int measureSpec) {
1372e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet        int result = 0;
1382e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet        int specMode = MeasureSpec.getMode(measureSpec);
1392e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet        int specSize = MeasureSpec.getSize(measureSpec);
1402e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet
1412e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet        if (specMode == MeasureSpec.EXACTLY) {
1422e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet            // We were told how big to be
1432e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet            result = specSize;
1442e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet        } else {
1452e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet            // Measure the text
1462e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet            result = (int) mTextPaint.measureText(mText) + getPaddingLeft()
1472e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet                    + getPaddingRight();
1482e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet            if (specMode == MeasureSpec.AT_MOST) {
1492e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet                // Respect AT_MOST value if that was what is called for by measureSpec
1502e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet                result = Math.min(result, specSize);
1512e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet            }
1522e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet        }
1532e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet
1542e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet        return result;
1552e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet    }
1562e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet
1572e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet    /**
1582e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet     * Determines the height of this view
1592e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet     * @param measureSpec A measureSpec packed into an int
1602e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet     * @return The height of the view, honoring constraints from measureSpec
1612e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet     */
1622e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet    private int measureHeight(int measureSpec) {
1632e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet        int result = 0;
1642e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet        int specMode = MeasureSpec.getMode(measureSpec);
1652e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet        int specSize = MeasureSpec.getSize(measureSpec);
1662e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet
1672e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet        mAscent = (int) mTextPaint.ascent();
1682e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet        if (specMode == MeasureSpec.EXACTLY) {
1692e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet            // We were told how big to be
1702e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet            result = specSize;
1712e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet        } else {
1722e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet            // Measure the text (beware: ascent is a negative number)
1732e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet            result = (int) (-mAscent + mTextPaint.descent()) + getPaddingTop()
1742e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet                    + getPaddingBottom();
1752e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet            if (specMode == MeasureSpec.AT_MOST) {
1762e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet                // Respect AT_MOST value if that was what is called for by measureSpec
1772e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet                result = Math.min(result, specSize);
1782e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet            }
1792e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet        }
1802e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet        return result;
1812e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet    }
1822e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet
1832e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet    /**
1842e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet     * Render the text
1852e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet     *
1862e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet     * @see android.view.View#onDraw(android.graphics.Canvas)
1872e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet     */
1882e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet    @Override
1892e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet    protected void onDraw(Canvas canvas) {
1902e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet        super.onDraw(canvas);
1912e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet        canvas.drawText(mText, getPaddingLeft(), getPaddingTop() - mAscent, mTextPaint);
1922e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet    }
1932e00a07d401e4ce62fe59ad492acc86ef6601a66Xavier Ducrohet}
194