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
18package com.android.mail.browse;
19
20import android.content.Context;
21import android.graphics.Canvas;
22import android.graphics.Paint;
23import android.graphics.Paint.FontMetricsInt;
24import android.graphics.Rect;
25import android.graphics.drawable.Drawable;
26import android.text.style.DynamicDrawableSpan;
27import android.text.style.ImageSpan;
28import android.text.style.ReplacementSpan;
29
30import java.lang.ref.WeakReference;
31
32/**
33 * Acts like an {@link ImageSpan}, with some important distinctions:
34 * <ol>
35 * <li>modifies font metrics in a manner consistent with {@link FolderSpan}
36 * (will not increase line height beyond {@link FolderSpan} height)</li>
37 * <li>draws its image vertically centered within its line</li>
38 * <li>allows horizontal and vertical padding</li>
39 * </ol>
40 * Much of this code was copied from {@link DynamicDrawableSpan} and ImageSpan
41 * because
42 * {@link DynamicDrawableSpan#draw(Canvas, CharSequence, int, int, float, int, int, int, Paint)}
43 * is difficult to override efficiently owing to the private getCachedDrawable()
44 * method (filed as bug 5354674).
45 */
46public class PriorityIndicatorSpan extends ReplacementSpan {
47
48    private final Context mContext;
49    private final int mResId;
50    private final int mPaddingV;
51    private final int mPaddingH;
52    private final int mPaddingAbove;
53
54    private WeakReference<Drawable> mDrawableRef;
55
56    public PriorityIndicatorSpan(Context context, int resId, int paddingV, int paddingH,
57            int paddingAbove) {
58        mContext = context;
59        mResId = resId;
60        mPaddingV = paddingV;
61        mPaddingH = paddingH;
62        mPaddingAbove = paddingAbove;
63    }
64
65    private Drawable getDrawable() {
66        Drawable d = mContext.getResources().getDrawable(mResId);
67        d.setBounds(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());
68        return d;
69    }
70
71    private Drawable getCachedDrawable() {
72        WeakReference<Drawable> wr = mDrawableRef;
73        Drawable d = null;
74
75        if (wr != null)
76            d = wr.get();
77
78        if (d == null) {
79            d = getDrawable();
80            mDrawableRef = new WeakReference<Drawable>(d);
81        }
82
83        return d;
84    }
85
86    @Override
87    public int getSize(Paint paint, CharSequence text, int start, int end, FontMetricsInt fm) {
88        Drawable d = getCachedDrawable();
89        Rect rect = d.getBounds();
90
91        if (fm != null) {
92            paint.getFontMetricsInt(fm);
93            fm.ascent -= mPaddingV;
94            fm.top = fm.ascent;
95            fm.bottom += mPaddingV;
96            fm.descent += mPaddingV;
97        }
98
99        return rect.right + 2 * mPaddingH;
100    }
101
102    @Override
103    public void draw(Canvas canvas, CharSequence text, int start, int end, float x, int top,
104            int y, int bottom, Paint paint) {
105        Drawable b = getCachedDrawable();
106        canvas.save();
107
108        final int transY = (top + bottom + mPaddingAbove - b.getBounds().bottom) / 2;
109
110        canvas.translate(x + mPaddingH, transY);
111        b.draw(canvas);
112        canvas.restore();
113    }
114
115}
116