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