Home | History | Annotate | Download | only in style
      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      */
     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      */
     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      */
    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 
    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 
    151     public int getSpanTypeId() {
    152         return getSpanTypeIdInternal();
    153     }
    154 
    155     /** @hide */
    156     public int getSpanTypeIdInternal() {
    157         return TextUtils.TEXT_APPEARANCE_SPAN;
    158     }
    159 
    160     public int describeContents() {
    161         return 0;
    162     }
    163 
    164     public void writeToParcel(Parcel dest, int flags) {
    165         writeToParcelInternal(dest, flags);
    166     }
    167 
    168     /** @hide */
    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      */
    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      */
    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      */
    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      */
    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      */
    224     public int getTextStyle() {
    225         return mStyle;
    226     }
    227 
    228     @Override
    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
    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