Home | History | Annotate | Download | only in style
      1 /*
      2  * Copyright (C) 2006 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.annotation.DrawableRes;
     20 import android.annotation.NonNull;
     21 import android.annotation.Nullable;
     22 import android.content.Context;
     23 import android.graphics.Bitmap;
     24 import android.graphics.BitmapFactory;
     25 import android.graphics.drawable.BitmapDrawable;
     26 import android.graphics.drawable.Drawable;
     27 import android.net.Uri;
     28 import android.util.Log;
     29 
     30 import java.io.InputStream;
     31 
     32 /**
     33  * Span that replaces the text it's attached to with a {@link Drawable} that can be aligned with
     34  * the bottom or with the baseline of the surrounding text. The drawable can be constructed from
     35  * varied sources:
     36  * <ul>
     37  * <li>{@link Bitmap} - see {@link #ImageSpan(Context, Bitmap)} and
     38  * {@link #ImageSpan(Context, Bitmap, int)}
     39  * </li>
     40  * <li>{@link Drawable} - see {@link #ImageSpan(Drawable, int)}</li>
     41  * <li>resource id - see {@link #ImageSpan(Context, int, int)}</li>
     42  * <li>{@link Uri} - see {@link #ImageSpan(Context, Uri, int)}</li>
     43  * </ul>
     44  * The default value for the vertical alignment is {@link DynamicDrawableSpan#ALIGN_BOTTOM}
     45  * <p>
     46  * For example, an <code>ImagedSpan</code> can be used like this:
     47  * <pre>
     48  * SpannableString string = SpannableString("Bottom: span.\nBaseline: span.");
     49  * // using the default alignment: ALIGN_BOTTOM
     50  * string.setSpan(ImageSpan(this, R.mipmap.ic_launcher), 7, 8, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
     51  * string.setSpan(ImageSpan(this, R.mipmap.ic_launcher, DynamicDrawableSpan.ALIGN_BASELINE),
     52  * 22, 23, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
     53  * </pre>
     54  * <img src="{@docRoot}reference/android/images/text/style/imagespan.png" />
     55  * <figcaption>Text with <code>ImageSpan</code>s aligned bottom and baseline.</figcaption>
     56  */
     57 public class ImageSpan extends DynamicDrawableSpan {
     58 
     59     @Nullable
     60     private Drawable mDrawable;
     61     @Nullable
     62     private Uri mContentUri;
     63     @DrawableRes
     64     private int mResourceId;
     65     @Nullable
     66     private Context mContext;
     67     @Nullable
     68     private String mSource;
     69 
     70     /**
     71      * @deprecated Use {@link #ImageSpan(Context, Bitmap)} instead.
     72      */
     73     @Deprecated
     74     public ImageSpan(@NonNull Bitmap b) {
     75         this(null, b, ALIGN_BOTTOM);
     76     }
     77 
     78     /**
     79      * @deprecated Use {@link #ImageSpan(Context, Bitmap, int)} instead.
     80      */
     81     @Deprecated
     82     public ImageSpan(@NonNull Bitmap b, int verticalAlignment) {
     83         this(null, b, verticalAlignment);
     84     }
     85 
     86     /**
     87      * Constructs an {@link ImageSpan} from a {@link Context} and a {@link Bitmap} with the default
     88      * alignment {@link DynamicDrawableSpan#ALIGN_BOTTOM}
     89      *
     90      * @param context context used to create a drawable from {@param bitmap} based on the display
     91      *                metrics of the resources
     92      * @param bitmap  bitmap to be rendered
     93      */
     94     public ImageSpan(@NonNull Context context, @NonNull Bitmap bitmap) {
     95         this(context, bitmap, ALIGN_BOTTOM);
     96     }
     97 
     98     /**
     99      * Constructs an {@link ImageSpan} from a {@link Context}, a {@link Bitmap} and a vertical
    100      * alignment.
    101      *
    102      * @param context           context used to create a drawable from {@param bitmap} based on
    103      *                          the display metrics of the resources
    104      * @param bitmap            bitmap to be rendered
    105      * @param verticalAlignment one of {@link DynamicDrawableSpan#ALIGN_BOTTOM} or
    106      *                          {@link DynamicDrawableSpan#ALIGN_BASELINE}
    107      */
    108     public ImageSpan(@NonNull Context context, @NonNull Bitmap bitmap, int verticalAlignment) {
    109         super(verticalAlignment);
    110         mContext = context;
    111         mDrawable = context != null
    112                 ? new BitmapDrawable(context.getResources(), bitmap)
    113                 : new BitmapDrawable(bitmap);
    114         int width = mDrawable.getIntrinsicWidth();
    115         int height = mDrawable.getIntrinsicHeight();
    116         mDrawable.setBounds(0, 0, width > 0 ? width : 0, height > 0 ? height : 0);
    117     }
    118 
    119     /**
    120      * Constructs an {@link ImageSpan} from a drawable with the default
    121      * alignment {@link DynamicDrawableSpan#ALIGN_BOTTOM}.
    122      *
    123      * @param drawable drawable to be rendered
    124      */
    125     public ImageSpan(@NonNull Drawable drawable) {
    126         this(drawable, ALIGN_BOTTOM);
    127     }
    128 
    129     /**
    130      * Constructs an {@link ImageSpan} from a drawable and a vertical alignment.
    131      *
    132      * @param drawable          drawable to be rendered
    133      * @param verticalAlignment one of {@link DynamicDrawableSpan#ALIGN_BOTTOM} or
    134      *                          {@link DynamicDrawableSpan#ALIGN_BASELINE}
    135      */
    136     public ImageSpan(@NonNull Drawable drawable, int verticalAlignment) {
    137         super(verticalAlignment);
    138         mDrawable = drawable;
    139     }
    140 
    141     /**
    142      * Constructs an {@link ImageSpan} from a drawable and a source with the default
    143      * alignment {@link DynamicDrawableSpan#ALIGN_BOTTOM}
    144      *
    145      * @param drawable drawable to be rendered
    146      * @param source   drawable's Uri source
    147      */
    148     public ImageSpan(@NonNull Drawable drawable, @NonNull String source) {
    149         this(drawable, source, ALIGN_BOTTOM);
    150     }
    151 
    152     /**
    153      * Constructs an {@link ImageSpan} from a drawable, a source and a vertical alignment.
    154      *
    155      * @param drawable          drawable to be rendered
    156      * @param source            drawable's uri source
    157      * @param verticalAlignment one of {@link DynamicDrawableSpan#ALIGN_BOTTOM} or
    158      *                          {@link DynamicDrawableSpan#ALIGN_BASELINE}
    159      */
    160     public ImageSpan(@NonNull Drawable drawable, @NonNull String source, int verticalAlignment) {
    161         super(verticalAlignment);
    162         mDrawable = drawable;
    163         mSource = source;
    164     }
    165 
    166     /**
    167      * Constructs an {@link ImageSpan} from a {@link Context} and a {@link Uri} with the default
    168      * alignment {@link DynamicDrawableSpan#ALIGN_BOTTOM}. The Uri source can be retrieved via
    169      * {@link #getSource()}
    170      *
    171      * @param context context used to create a drawable from {@param bitmap} based on the display
    172      *                metrics of the resources
    173      * @param uri     {@link Uri} used to construct the drawable that will be rendered
    174      */
    175     public ImageSpan(@NonNull Context context, @NonNull Uri uri) {
    176         this(context, uri, ALIGN_BOTTOM);
    177     }
    178 
    179     /**
    180      * Constructs an {@link ImageSpan} from a {@link Context}, a {@link Uri} and a vertical
    181      * alignment. The Uri source can be retrieved via {@link #getSource()}
    182      *
    183      * @param context           context used to create a drawable from {@param bitmap} based on
    184      *                          the display
    185      *                          metrics of the resources
    186      * @param uri               {@link Uri} used to construct the drawable that will be rendered.
    187      * @param verticalAlignment one of {@link DynamicDrawableSpan#ALIGN_BOTTOM} or
    188      *                          {@link DynamicDrawableSpan#ALIGN_BASELINE}
    189      */
    190     public ImageSpan(@NonNull Context context, @NonNull Uri uri, int verticalAlignment) {
    191         super(verticalAlignment);
    192         mContext = context;
    193         mContentUri = uri;
    194         mSource = uri.toString();
    195     }
    196 
    197     /**
    198      * Constructs an {@link ImageSpan} from a {@link Context} and a resource id with the default
    199      * alignment {@link DynamicDrawableSpan#ALIGN_BOTTOM}
    200      *
    201      * @param context    context used to retrieve the drawable from resources
    202      * @param resourceId drawable resource id based on which the drawable is retrieved
    203      */
    204     public ImageSpan(@NonNull Context context, @DrawableRes int resourceId) {
    205         this(context, resourceId, ALIGN_BOTTOM);
    206     }
    207 
    208     /**
    209      * Constructs an {@link ImageSpan} from a {@link Context}, a resource id and a vertical
    210      * alignment.
    211      *
    212      * @param context           context used to retrieve the drawable from resources
    213      * @param resourceId        drawable resource id based on which the drawable is retrieved.
    214      * @param verticalAlignment one of {@link DynamicDrawableSpan#ALIGN_BOTTOM} or
    215      *                          {@link DynamicDrawableSpan#ALIGN_BASELINE}
    216      */
    217     public ImageSpan(@NonNull Context context, @DrawableRes int resourceId,
    218             int verticalAlignment) {
    219         super(verticalAlignment);
    220         mContext = context;
    221         mResourceId = resourceId;
    222     }
    223 
    224     @Override
    225     public Drawable getDrawable() {
    226         Drawable drawable = null;
    227 
    228         if (mDrawable != null) {
    229             drawable = mDrawable;
    230         } else if (mContentUri != null) {
    231             Bitmap bitmap = null;
    232             try {
    233                 InputStream is = mContext.getContentResolver().openInputStream(
    234                         mContentUri);
    235                 bitmap = BitmapFactory.decodeStream(is);
    236                 drawable = new BitmapDrawable(mContext.getResources(), bitmap);
    237                 drawable.setBounds(0, 0, drawable.getIntrinsicWidth(),
    238                         drawable.getIntrinsicHeight());
    239                 is.close();
    240             } catch (Exception e) {
    241                 Log.e("ImageSpan", "Failed to loaded content " + mContentUri, e);
    242             }
    243         } else {
    244             try {
    245                 drawable = mContext.getDrawable(mResourceId);
    246                 drawable.setBounds(0, 0, drawable.getIntrinsicWidth(),
    247                         drawable.getIntrinsicHeight());
    248             } catch (Exception e) {
    249                 Log.e("ImageSpan", "Unable to find resource: " + mResourceId);
    250             }
    251         }
    252 
    253         return drawable;
    254     }
    255 
    256     /**
    257      * Returns the source string that was saved during construction.
    258      *
    259      * @return the source string that was saved during construction
    260      * @see #ImageSpan(Drawable, String) and this{@link #ImageSpan(Context, Uri)}
    261      */
    262     @Nullable
    263     public String getSource() {
    264         return mSource;
    265     }
    266 }
    267