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 
18 package com.android.mail.browse;
19 
20 import android.graphics.Canvas;
21 import android.graphics.Paint;
22 import android.graphics.Paint.FontMetricsInt;
23 import android.graphics.RectF;
24 import android.text.Spanned;
25 import android.text.TextPaint;
26 import android.text.style.CharacterStyle;
27 import 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  */
34 public 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          */
getHorizontalPadding()41         int getHorizontalPadding();
42 
43         /**
44          * Returns the radius to use for the rounded corners on the background rect.
45          */
getRoundedCornerRadius()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 
BadgeSpan(Spanned spanned, BadgeSpanDimensions dims)57     public BadgeSpan(Spanned spanned, BadgeSpanDimensions dims) {
58         mSpanned = spanned;
59         mDims = dims;
60     }
61 
62     @Override
getSize(Paint paint, CharSequence text, int start, int end, FontMetricsInt fm)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 
measureWidth(Paint paint, CharSequence text, int start, int end)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
draw(Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, Paint paint)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