1 /* 2 * Copyright (C) 2012 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.text.Spanned; 24 import android.text.TextPaint; 25 import android.text.TextUtils; 26 import android.text.style.CharacterStyle; 27 import android.text.style.ReplacementSpan; 28 29 /** 30 * A replacement span to use when displaying folders in conversation view. Prevents a folder name 31 * from wrapping mid-name, and ellipsizes very long folder names that can't fit on a single line. 32 * Also ensures that folder text is drawn vertically centered within the background color chip. 33 * 34 */ 35 public class FolderSpan extends ReplacementSpan { 36 37 public interface FolderSpanDimensions { getPadding()38 int getPadding(); 39 40 /** 41 * Returns the padding value that corresponds to the horizontal padding 42 * surrounding the text inside the background color. 43 */ getPaddingExtraWidth()44 int getPaddingExtraWidth(); 45 46 /** 47 * Returns the padding value for the space between folders. 48 */ getPaddingBefore()49 int getPaddingBefore(); 50 51 /** 52 * Returns the spacing above each line outside of the . 53 */ getPaddingAbove()54 int getPaddingAbove(); getMaxWidth()55 int getMaxWidth(); 56 } 57 58 private TextPaint mWorkPaint = new TextPaint(); 59 /** 60 * A reference to the enclosing Spanned object to collect other CharacterStyle spans and take 61 * them into account when drawing. 62 */ 63 private final Spanned mSpanned; 64 private final FolderSpanDimensions mDims; 65 FolderSpan(Spanned spanned, FolderSpanDimensions dims)66 public FolderSpan(Spanned spanned, FolderSpanDimensions dims) { 67 mSpanned = spanned; 68 mDims = dims; 69 } 70 71 @Override getSize(Paint paint, CharSequence text, int start, int end, FontMetricsInt fm)72 public int getSize(Paint paint, CharSequence text, int start, int end, FontMetricsInt fm) { 73 if (fm != null) { 74 final int paddingV = mDims.getPadding(); 75 paint.getFontMetricsInt(fm); 76 // The magic set of measurements to vertically center text within a colored region! 77 fm.ascent -= paddingV; 78 fm.top = fm.ascent; 79 fm.bottom += paddingV; 80 fm.descent += paddingV; 81 } 82 return measureWidth(paint, text, start, end, true); 83 } 84 measureWidth(Paint paint, CharSequence text, int start, int end, boolean includePaddingBefore)85 private int measureWidth(Paint paint, CharSequence text, int start, int end, 86 boolean includePaddingBefore) { 87 final int paddingW = mDims.getPadding() + mDims.getPaddingExtraWidth(); 88 final int maxWidth = mDims.getMaxWidth(); 89 90 int w = (int) paint.measureText(text, start, end) + 2 * paddingW; 91 if (includePaddingBefore) { 92 w += mDims.getPaddingBefore(); 93 } 94 // TextView doesn't handle spans that are wider than the view very well, so cap their widths 95 if (w > maxWidth) { 96 w = maxWidth; 97 } 98 return w; 99 } 100 101 @Override draw(Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, Paint paint)102 public void draw(Canvas canvas, CharSequence text, int start, int end, float x, int top, 103 int y, int bottom, Paint paint) { 104 105 final int paddingW = mDims.getPadding() + mDims.getPaddingExtraWidth(); 106 final int paddingBefore = mDims.getPaddingBefore(); 107 final int paddingAbove = mDims.getPaddingAbove(); 108 final int maxWidth = mDims.getMaxWidth(); 109 110 mWorkPaint.set(paint); 111 112 // take into account the foreground/background color spans when painting 113 final CharacterStyle[] otherSpans = mSpanned.getSpans(start, end, CharacterStyle.class); 114 for (CharacterStyle otherSpan : otherSpans) { 115 otherSpan.updateDrawState(mWorkPaint); 116 } 117 118 final int bgWidth = measureWidth(mWorkPaint, text, start, end, false); 119 120 // paint a background if present 121 if (mWorkPaint.bgColor != 0) { 122 final int prevColor = mWorkPaint.getColor(); 123 final Paint.Style prevStyle = mWorkPaint.getStyle(); 124 125 mWorkPaint.setColor(mWorkPaint.bgColor); 126 mWorkPaint.setStyle(Paint.Style.FILL); 127 canvas.drawRect(x + paddingBefore, top + paddingAbove, x + bgWidth + paddingBefore, bottom, 128 mWorkPaint); 129 130 mWorkPaint.setColor(prevColor); 131 mWorkPaint.setStyle(prevStyle); 132 } 133 134 // middle-ellipsize long strings 135 if (bgWidth == maxWidth) { 136 text = TextUtils.ellipsize(text.subSequence(start, end).toString(), mWorkPaint, 137 bgWidth - 2 * paddingW, TextUtils.TruncateAt.MIDDLE); 138 start = 0; 139 end = text.length(); 140 } 141 canvas.drawText(text, start, end, x + paddingW + paddingBefore, y + paddingAbove, mWorkPaint); 142 } 143 144 } 145