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