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.LeakyTypefaceStorage; 23 import android.graphics.Typeface; 24 import android.os.Parcel; 25 import android.text.ParcelableSpan; 26 import android.text.TextPaint; 27 import android.text.TextUtils; 28 29 /** 30 * Sets the text color, size, style, and typeface to match a TextAppearance 31 * resource. 32 */ 33 public class TextAppearanceSpan extends MetricAffectingSpan implements ParcelableSpan { 34 private final String mFamilyName; 35 private final int mStyle; 36 private final int mTextSize; 37 private final ColorStateList mTextColor; 38 private final ColorStateList mTextColorLink; 39 private final Typeface mTypeface; 40 41 /** 42 * Uses the specified TextAppearance resource to determine the 43 * text appearance. The <code>appearance</code> should be, for example, 44 * <code>android.R.style.TextAppearance_Small</code>. 45 */ TextAppearanceSpan(Context context, int appearance)46 public TextAppearanceSpan(Context context, int appearance) { 47 this(context, appearance, -1); 48 } 49 50 /** 51 * Uses the specified TextAppearance resource to determine the 52 * text appearance, and the specified text color resource 53 * to determine the color. The <code>appearance</code> should be, 54 * for example, <code>android.R.style.TextAppearance_Small</code>, 55 * and the <code>colorList</code> should be, for example, 56 * <code>android.R.styleable.Theme_textColorPrimary</code>. 57 */ TextAppearanceSpan(Context context, int appearance, int colorList)58 public TextAppearanceSpan(Context context, int appearance, int colorList) { 59 ColorStateList textColor; 60 61 TypedArray a = 62 context.obtainStyledAttributes(appearance, 63 com.android.internal.R.styleable.TextAppearance); 64 65 textColor = a.getColorStateList(com.android.internal.R.styleable. 66 TextAppearance_textColor); 67 mTextColorLink = a.getColorStateList(com.android.internal.R.styleable. 68 TextAppearance_textColorLink); 69 mTextSize = a.getDimensionPixelSize(com.android.internal.R.styleable. 70 TextAppearance_textSize, -1); 71 72 mStyle = a.getInt(com.android.internal.R.styleable.TextAppearance_textStyle, 0); 73 if (!context.isRestricted() && context.canLoadUnsafeResources()) { 74 mTypeface = a.getFont(com.android.internal.R.styleable.TextAppearance_fontFamily); 75 } else { 76 mTypeface = null; 77 } 78 if (mTypeface != null) { 79 mFamilyName = null; 80 } else { 81 String family = a.getString(com.android.internal.R.styleable.TextAppearance_fontFamily); 82 if (family != null) { 83 mFamilyName = family; 84 } else { 85 int tf = a.getInt(com.android.internal.R.styleable.TextAppearance_typeface, 0); 86 87 switch (tf) { 88 case 1: 89 mFamilyName = "sans"; 90 break; 91 92 case 2: 93 mFamilyName = "serif"; 94 break; 95 96 case 3: 97 mFamilyName = "monospace"; 98 break; 99 100 default: 101 mFamilyName = null; 102 break; 103 } 104 } 105 } 106 107 a.recycle(); 108 109 if (colorList >= 0) { 110 a = context.obtainStyledAttributes(com.android.internal.R.style.Theme, 111 com.android.internal.R.styleable.Theme); 112 113 textColor = a.getColorStateList(colorList); 114 a.recycle(); 115 } 116 117 mTextColor = textColor; 118 } 119 120 /** 121 * Makes text be drawn with the specified typeface, size, style, 122 * and colors. 123 */ TextAppearanceSpan(String family, int style, int size, ColorStateList color, ColorStateList linkColor)124 public TextAppearanceSpan(String family, int style, int size, 125 ColorStateList color, ColorStateList linkColor) { 126 mFamilyName = family; 127 mStyle = style; 128 mTextSize = size; 129 mTextColor = color; 130 mTextColorLink = linkColor; 131 mTypeface = null; 132 } 133 TextAppearanceSpan(Parcel src)134 public TextAppearanceSpan(Parcel src) { 135 mFamilyName = src.readString(); 136 mStyle = src.readInt(); 137 mTextSize = src.readInt(); 138 if (src.readInt() != 0) { 139 mTextColor = ColorStateList.CREATOR.createFromParcel(src); 140 } else { 141 mTextColor = null; 142 } 143 if (src.readInt() != 0) { 144 mTextColorLink = ColorStateList.CREATOR.createFromParcel(src); 145 } else { 146 mTextColorLink = null; 147 } 148 mTypeface = LeakyTypefaceStorage.readTypefaceFromParcel(src); 149 } 150 getSpanTypeId()151 public int getSpanTypeId() { 152 return getSpanTypeIdInternal(); 153 } 154 155 /** @hide */ getSpanTypeIdInternal()156 public int getSpanTypeIdInternal() { 157 return TextUtils.TEXT_APPEARANCE_SPAN; 158 } 159 describeContents()160 public int describeContents() { 161 return 0; 162 } 163 writeToParcel(Parcel dest, int flags)164 public void writeToParcel(Parcel dest, int flags) { 165 writeToParcelInternal(dest, flags); 166 } 167 168 /** @hide */ writeToParcelInternal(Parcel dest, int flags)169 public void writeToParcelInternal(Parcel dest, int flags) { 170 dest.writeString(mFamilyName); 171 dest.writeInt(mStyle); 172 dest.writeInt(mTextSize); 173 if (mTextColor != null) { 174 dest.writeInt(1); 175 mTextColor.writeToParcel(dest, flags); 176 } else { 177 dest.writeInt(0); 178 } 179 if (mTextColorLink != null) { 180 dest.writeInt(1); 181 mTextColorLink.writeToParcel(dest, flags); 182 } else { 183 dest.writeInt(0); 184 } 185 LeakyTypefaceStorage.writeTypefaceToParcel(mTypeface, dest); 186 } 187 188 /** 189 * Returns the typeface family specified by this span, or <code>null</code> 190 * if it does not specify one. 191 */ getFamily()192 public String getFamily() { 193 return mFamilyName; 194 } 195 196 /** 197 * Returns the text color specified by this span, or <code>null</code> 198 * if it does not specify one. 199 */ getTextColor()200 public ColorStateList getTextColor() { 201 return mTextColor; 202 } 203 204 /** 205 * Returns the link color specified by this span, or <code>null</code> 206 * if it does not specify one. 207 */ getLinkTextColor()208 public ColorStateList getLinkTextColor() { 209 return mTextColorLink; 210 } 211 212 /** 213 * Returns the text size specified by this span, or <code>-1</code> 214 * if it does not specify one. 215 */ getTextSize()216 public int getTextSize() { 217 return mTextSize; 218 } 219 220 /** 221 * Returns the text style specified by this span, or <code>0</code> 222 * if it does not specify one. 223 */ getTextStyle()224 public int getTextStyle() { 225 return mStyle; 226 } 227 228 @Override updateDrawState(TextPaint ds)229 public void updateDrawState(TextPaint ds) { 230 updateMeasureState(ds); 231 232 if (mTextColor != null) { 233 ds.setColor(mTextColor.getColorForState(ds.drawableState, 0)); 234 } 235 236 if (mTextColorLink != null) { 237 ds.linkColor = mTextColorLink.getColorForState(ds.drawableState, 0); 238 } 239 } 240 241 @Override updateMeasureState(TextPaint ds)242 public void updateMeasureState(TextPaint ds) { 243 final Typeface styledTypeface; 244 int style = 0; 245 246 if (mTypeface != null) { 247 style = mStyle; 248 styledTypeface = Typeface.create(mTypeface, style); 249 } else if (mFamilyName != null || mStyle != 0) { 250 Typeface tf = ds.getTypeface(); 251 252 if (tf != null) { 253 style = tf.getStyle(); 254 } 255 256 style |= mStyle; 257 258 if (mFamilyName != null) { 259 styledTypeface = Typeface.create(mFamilyName, style); 260 } else if (tf == null) { 261 styledTypeface = Typeface.defaultFromStyle(style); 262 } else { 263 styledTypeface = Typeface.create(tf, style); 264 } 265 } else { 266 styledTypeface = null; 267 } 268 269 if (styledTypeface != null) { 270 int fake = style & ~styledTypeface.getStyle(); 271 272 if ((fake & Typeface.BOLD) != 0) { 273 ds.setFakeBoldText(true); 274 } 275 276 if ((fake & Typeface.ITALIC) != 0) { 277 ds.setTextSkewX(-0.25f); 278 } 279 280 ds.setTypeface(styledTypeface); 281 } 282 283 if (mTextSize > 0) { 284 ds.setTextSize(mTextSize); 285 } 286 } 287 } 288