1be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein/*
2be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein * Copyright (C) 2014 Google Inc.
3be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein * Licensed to The Android Open Source Project.
4be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein *
5be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein * Licensed under the Apache License, Version 2.0 (the "License");
6be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein * you may not use this file except in compliance with the License.
7be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein * You may obtain a copy of the License at
8be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein *
9be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein *      http://www.apache.org/licenses/LICENSE-2.0
10be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein *
11be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein * Unless required by applicable law or agreed to in writing, software
12be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein * distributed under the License is distributed on an "AS IS" BASIS,
13be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein * See the License for the specific language governing permissions and
15be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein * limitations under the License.
16be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein */
17be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein
18be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sappersteinpackage com.android.mail.browse;
19be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein
20be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sappersteinimport android.graphics.Canvas;
21be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sappersteinimport android.graphics.Paint;
22be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sappersteinimport android.graphics.Paint.FontMetricsInt;
23be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sappersteinimport android.graphics.RectF;
24be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sappersteinimport android.text.Spanned;
25be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sappersteinimport android.text.TextPaint;
26be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sappersteinimport android.text.style.CharacterStyle;
27be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sappersteinimport android.text.style.ReplacementSpan;
28be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein
29be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein/**
30be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein * A replacement span to use when displaying a badge in a conversation list item.
31be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein * A badge will be some piece of text with a colored background and rounded
32be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein * corners.
33be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein */
34be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sappersteinpublic class BadgeSpan extends ReplacementSpan {
35be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein
36be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein    public interface BadgeSpanDimensions {
37be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein        /**
38be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein         * Returns the padding value that corresponds to one side of the
39be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein         * horizontal padding surrounding the text inside the background color.
40be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein         */
41be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein        int getHorizontalPadding();
42be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein
43be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein        /**
44be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein         * Returns the radius to use for the rounded corners on the background rect.
45be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein         */
46be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein        float getRoundedCornerRadius();
47be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein    }
48be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein
49be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein    private TextPaint mWorkPaint = new TextPaint();
50be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein    /**
51be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein     * A reference to the enclosing Spanned object to collect other CharacterStyle spans and take
52be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein     * them into account when drawing.
53be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein     */
54be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein    private final Spanned mSpanned;
55be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein    private final BadgeSpanDimensions mDims;
56be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein
57be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein    public BadgeSpan(Spanned spanned, BadgeSpanDimensions dims) {
58be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein        mSpanned = spanned;
59be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein        mDims = dims;
60be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein    }
61be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein
62be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein    @Override
63be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein    public int getSize(Paint paint, CharSequence text, int start, int end, FontMetricsInt fm) {
64be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein        if (fm != null) {
65be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein            paint.getFontMetricsInt(fm);
66be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein            // The magic set of measurements to vertically center text within a colored region!
67be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein            fm.top = fm.ascent;
68be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein        }
69be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein        return measureWidth(paint, text, start, end);
70be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein    }
71be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein
72be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein    private int measureWidth(Paint paint, CharSequence text, int start, int end) {
73be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein        return (int) paint.measureText(text, start, end) + 2 * mDims.getHorizontalPadding();
74be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein    }
75be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein
76be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein    @Override
77be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein    public void draw(Canvas canvas, CharSequence text, int start, int end, float x, int top,
78be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein            int y, int bottom, Paint paint) {
79be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein
80be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein        mWorkPaint.set(paint);
81be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein
82be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein        // take into account the foreground/background color spans when painting
83be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein        final CharacterStyle[] otherSpans = mSpanned.getSpans(start, end, CharacterStyle.class);
84be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein        for (CharacterStyle otherSpan : otherSpans) {
85be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein            otherSpan.updateDrawState(mWorkPaint);
86be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein        }
87be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein
88be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein        // paint a background if present
89be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein        if (mWorkPaint.bgColor != 0) {
90be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein            final int prevColor = mWorkPaint.getColor();
91be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein            final Paint.Style prevStyle = mWorkPaint.getStyle();
92be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein
93be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein            mWorkPaint.setColor(mWorkPaint.bgColor);
94be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein            mWorkPaint.setStyle(Paint.Style.FILL);
95be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein
96be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein            final int bgWidth = measureWidth(mWorkPaint, text, start, end);
97be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein            final RectF rect = new RectF(x, top, x + bgWidth, bottom);
98be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein            final float radius = mDims.getRoundedCornerRadius();
99be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein            canvas.drawRoundRect(rect, radius, radius, mWorkPaint);
100be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein
101be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein            mWorkPaint.setColor(prevColor);
102be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein            mWorkPaint.setStyle(prevStyle);
103be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein        }
104be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein
105be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein        canvas.drawText(text, start, end, x + mDims.getHorizontalPadding(), y, mWorkPaint);
106be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein    }
107be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein}
108