1 /*
2  * Copyright (C) 2008 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.text.style;
18 
19 import android.content.Context;
20 import android.content.res.ColorStateList;
21 import android.content.res.TypedArray;
22 import android.graphics.Typeface;
23 import android.os.Parcel;
24 import android.text.ParcelableSpan;
25 import android.text.TextPaint;
26 import android.text.TextUtils;
27 
28 /**
29  * Sets the text color, size, style, and typeface to match a TextAppearance
30  * resource.
31  */
32 public class TextAppearanceSpan extends MetricAffectingSpan implements ParcelableSpan {
33     private final String mTypeface;
34     private final int mStyle;
35     private final int mTextSize;
36     private final ColorStateList mTextColor;
37     private final ColorStateList mTextColorLink;
38 
39     /**
40      * Uses the specified TextAppearance resource to determine the
41      * text appearance.  The <code>appearance</code> should be, for example,
42      * <code>android.R.style.TextAppearance_Small</code>.
43      */
TextAppearanceSpan(Context context, int appearance)44     public TextAppearanceSpan(Context context, int appearance) {
45         this(context, appearance, -1);
46     }
47 
48     /**
49      * Uses the specified TextAppearance resource to determine the
50      * text appearance, and the specified text color resource
51      * to determine the color.  The <code>appearance</code> should be,
52      * for example, <code>android.R.style.TextAppearance_Small</code>,
53      * and the <code>colorList</code> should be, for example,
54      * <code>android.R.styleable.Theme_textColorPrimary</code>.
55      */
TextAppearanceSpan(Context context, int appearance, int colorList)56     public TextAppearanceSpan(Context context, int appearance, int colorList) {
57         ColorStateList textColor;
58 
59         TypedArray a =
60             context.obtainStyledAttributes(appearance,
61                                            com.android.internal.R.styleable.TextAppearance);
62 
63         textColor = a.getColorStateList(com.android.internal.R.styleable.
64                                         TextAppearance_textColor);
65         mTextColorLink = a.getColorStateList(com.android.internal.R.styleable.
66                                         TextAppearance_textColorLink);
67         mTextSize = a.getDimensionPixelSize(com.android.internal.R.styleable.
68                                         TextAppearance_textSize, -1);
69 
70         mStyle = a.getInt(com.android.internal.R.styleable.TextAppearance_textStyle, 0);
71         String family = a.getString(com.android.internal.R.styleable.TextAppearance_fontFamily);
72         if (family != null) {
73             mTypeface = family;
74         } else {
75             int tf = a.getInt(com.android.internal.R.styleable.TextAppearance_typeface, 0);
76 
77             switch (tf) {
78                 case 1:
79                     mTypeface = "sans";
80                     break;
81 
82                 case 2:
83                     mTypeface = "serif";
84                     break;
85 
86                 case 3:
87                     mTypeface = "monospace";
88                     break;
89 
90                 default:
91                     mTypeface = null;
92                     break;
93             }
94         }
95 
96         a.recycle();
97 
98         if (colorList >= 0) {
99             a = context.obtainStyledAttributes(com.android.internal.R.style.Theme,
100                                             com.android.internal.R.styleable.Theme);
101 
102             textColor = a.getColorStateList(colorList);
103             a.recycle();
104         }
105 
106         mTextColor = textColor;
107     }
108 
109     /**
110      * Makes text be drawn with the specified typeface, size, style,
111      * and colors.
112      */
TextAppearanceSpan(String family, int style, int size, ColorStateList color, ColorStateList linkColor)113     public TextAppearanceSpan(String family, int style, int size,
114                               ColorStateList color, ColorStateList linkColor) {
115         mTypeface = family;
116         mStyle = style;
117         mTextSize = size;
118         mTextColor = color;
119         mTextColorLink = linkColor;
120     }
121 
TextAppearanceSpan(Parcel src)122     public TextAppearanceSpan(Parcel src) {
123         mTypeface = src.readString();
124         mStyle = src.readInt();
125         mTextSize = src.readInt();
126         if (src.readInt() != 0) {
127             mTextColor = ColorStateList.CREATOR.createFromParcel(src);
128         } else {
129             mTextColor = null;
130         }
131         if (src.readInt() != 0) {
132             mTextColorLink = ColorStateList.CREATOR.createFromParcel(src);
133         } else {
134             mTextColorLink = null;
135         }
136     }
137 
getSpanTypeId()138     public int getSpanTypeId() {
139         return getSpanTypeIdInternal();
140     }
141 
142     /** @hide */
getSpanTypeIdInternal()143     public int getSpanTypeIdInternal() {
144         return TextUtils.TEXT_APPEARANCE_SPAN;
145     }
146 
describeContents()147     public int describeContents() {
148         return 0;
149     }
150 
writeToParcel(Parcel dest, int flags)151     public void writeToParcel(Parcel dest, int flags) {
152         writeToParcelInternal(dest, flags);
153     }
154 
155     /** @hide */
writeToParcelInternal(Parcel dest, int flags)156     public void writeToParcelInternal(Parcel dest, int flags) {
157         dest.writeString(mTypeface);
158         dest.writeInt(mStyle);
159         dest.writeInt(mTextSize);
160         if (mTextColor != null) {
161             dest.writeInt(1);
162             mTextColor.writeToParcel(dest, flags);
163         } else {
164             dest.writeInt(0);
165         }
166         if (mTextColorLink != null) {
167             dest.writeInt(1);
168             mTextColorLink.writeToParcel(dest, flags);
169         } else {
170             dest.writeInt(0);
171         }
172     }
173 
174     /**
175      * Returns the typeface family specified by this span, or <code>null</code>
176      * if it does not specify one.
177      */
getFamily()178     public String getFamily() {
179         return mTypeface;
180     }
181 
182     /**
183      * Returns the text color specified by this span, or <code>null</code>
184      * if it does not specify one.
185      */
getTextColor()186     public ColorStateList getTextColor() {
187         return mTextColor;
188     }
189 
190     /**
191      * Returns the link color specified by this span, or <code>null</code>
192      * if it does not specify one.
193      */
getLinkTextColor()194     public ColorStateList getLinkTextColor() {
195         return mTextColorLink;
196     }
197 
198     /**
199      * Returns the text size specified by this span, or <code>-1</code>
200      * if it does not specify one.
201      */
getTextSize()202     public int getTextSize() {
203         return mTextSize;
204     }
205 
206     /**
207      * Returns the text style specified by this span, or <code>0</code>
208      * if it does not specify one.
209      */
getTextStyle()210     public int getTextStyle() {
211         return mStyle;
212     }
213 
214     @Override
updateDrawState(TextPaint ds)215     public void updateDrawState(TextPaint ds) {
216         updateMeasureState(ds);
217 
218         if (mTextColor != null) {
219             ds.setColor(mTextColor.getColorForState(ds.drawableState, 0));
220         }
221 
222         if (mTextColorLink != null) {
223             ds.linkColor = mTextColorLink.getColorForState(ds.drawableState, 0);
224         }
225     }
226 
227     @Override
updateMeasureState(TextPaint ds)228     public void updateMeasureState(TextPaint ds) {
229         if (mTypeface != null || mStyle != 0) {
230             Typeface tf = ds.getTypeface();
231             int style = 0;
232 
233             if (tf != null) {
234                 style = tf.getStyle();
235             }
236 
237             style |= mStyle;
238 
239             if (mTypeface != null) {
240                 tf = Typeface.create(mTypeface, style);
241             } else if (tf == null) {
242                 tf = Typeface.defaultFromStyle(style);
243             } else {
244                 tf = Typeface.create(tf, style);
245             }
246 
247             int fake = style & ~tf.getStyle();
248 
249             if ((fake & Typeface.BOLD) != 0) {
250                 ds.setFakeBoldText(true);
251             }
252 
253             if ((fake & Typeface.ITALIC) != 0) {
254                 ds.setTextSkewX(-0.25f);
255             }
256 
257             ds.setTypeface(tf);
258         }
259 
260         if (mTextSize > 0) {
261             ds.setTextSize(mTextSize);
262         }
263     }
264 }
265