Home | History | Annotate | Download | only in content
      1 /**
      2  * Copyright (c) 2010, 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.content;
     18 
     19 import android.os.Parcel;
     20 import android.os.Parcelable;
     21 import android.os.PersistableBundle;
     22 import android.text.TextUtils;
     23 
     24 import java.util.ArrayList;
     25 
     26 /**
     27  * Meta-data describing the contents of a {@link ClipData}.  Provides enough
     28  * information to know if you can handle the ClipData, but not the data
     29  * itself.
     30  *
     31  * <div class="special reference">
     32  * <h3>Developer Guides</h3>
     33  * <p>For more information about using the clipboard framework, read the
     34  * <a href="{@docRoot}guide/topics/clipboard/copy-paste.html">Copy and Paste</a>
     35  * developer guide.</p>
     36  * </div>
     37  */
     38 public class ClipDescription implements Parcelable {
     39     /**
     40      * The MIME type for a clip holding plain text.
     41      */
     42     public static final String MIMETYPE_TEXT_PLAIN = "text/plain";
     43 
     44     /**
     45      * The MIME type for a clip holding HTML text.
     46      */
     47     public static final String MIMETYPE_TEXT_HTML = "text/html";
     48 
     49     /**
     50      * The MIME type for a clip holding one or more URIs.  This should be
     51      * used for URIs that are meaningful to a user (such as an http: URI).
     52      * It should <em>not</em> be used for a content: URI that references some
     53      * other piece of data; in that case the MIME type should be the type
     54      * of the referenced data.
     55      */
     56     public static final String MIMETYPE_TEXT_URILIST = "text/uri-list";
     57 
     58     /**
     59      * The MIME type for a clip holding an Intent.
     60      */
     61     public static final String MIMETYPE_TEXT_INTENT = "text/vnd.android.intent";
     62 
     63     /**
     64      * The name of the extra used to define a component name when copying/dragging
     65      * an app icon from Launcher.
     66      * <p>
     67      * Type: String
     68      * </p>
     69      * <p>
     70      * Use {@link ComponentName#unflattenFromString(String)}
     71      * and {@link ComponentName#flattenToString()} to convert the extra value
     72      * to/from {@link ComponentName}.
     73      * </p>
     74      * @hide
     75      */
     76     public static final String EXTRA_TARGET_COMPONENT_NAME =
     77             "android.content.extra.TARGET_COMPONENT_NAME";
     78 
     79     /**
     80      * The name of the extra used to define a user serial number when copying/dragging
     81      * an app icon from Launcher.
     82      * <p>
     83      * Type: long
     84      * </p>
     85      * @hide
     86      */
     87     public static final String EXTRA_USER_SERIAL_NUMBER =
     88             "android.content.extra.USER_SERIAL_NUMBER";
     89 
     90 
     91     final CharSequence mLabel;
     92     final String[] mMimeTypes;
     93     private PersistableBundle mExtras;
     94 
     95     /**
     96      * Create a new clip.
     97      *
     98      * @param label Label to show to the user describing this clip.
     99      * @param mimeTypes An array of MIME types this data is available as.
    100      */
    101     public ClipDescription(CharSequence label, String[] mimeTypes) {
    102         if (mimeTypes == null) {
    103             throw new NullPointerException("mimeTypes is null");
    104         }
    105         mLabel = label;
    106         mMimeTypes = mimeTypes;
    107     }
    108 
    109     /**
    110      * Create a copy of a ClipDescription.
    111      */
    112     public ClipDescription(ClipDescription o) {
    113         mLabel = o.mLabel;
    114         mMimeTypes = o.mMimeTypes;
    115     }
    116 
    117     /**
    118      * Helper to compare two MIME types, where one may be a pattern.
    119      * @param concreteType A fully-specified MIME type.
    120      * @param desiredType A desired MIME type that may be a pattern such as *&#47;*.
    121      * @return Returns true if the two MIME types match.
    122      */
    123     public static boolean compareMimeTypes(String concreteType, String desiredType) {
    124         final int typeLength = desiredType.length();
    125         if (typeLength == 3 && desiredType.equals("*/*")) {
    126             return true;
    127         }
    128 
    129         final int slashpos = desiredType.indexOf('/');
    130         if (slashpos > 0) {
    131             if (typeLength == slashpos+2 && desiredType.charAt(slashpos+1) == '*') {
    132                 if (desiredType.regionMatches(0, concreteType, 0, slashpos+1)) {
    133                     return true;
    134                 }
    135             } else if (desiredType.equals(concreteType)) {
    136                 return true;
    137             }
    138         }
    139 
    140         return false;
    141     }
    142 
    143     /**
    144      * Return the label for this clip.
    145      */
    146     public CharSequence getLabel() {
    147         return mLabel;
    148     }
    149 
    150     /**
    151      * Check whether the clip description contains the given MIME type.
    152      *
    153      * @param mimeType The desired MIME type.  May be a pattern.
    154      * @return Returns true if one of the MIME types in the clip description
    155      * matches the desired MIME type, else false.
    156      */
    157     public boolean hasMimeType(String mimeType) {
    158         for (int i=0; i<mMimeTypes.length; i++) {
    159             if (compareMimeTypes(mMimeTypes[i], mimeType)) {
    160                 return true;
    161             }
    162         }
    163         return false;
    164     }
    165 
    166     /**
    167      * Filter the clip description MIME types by the given MIME type.  Returns
    168      * all MIME types in the clip that match the given MIME type.
    169      *
    170      * @param mimeType The desired MIME type.  May be a pattern.
    171      * @return Returns an array of all matching MIME types.  If there are no
    172      * matching MIME types, null is returned.
    173      */
    174     public String[] filterMimeTypes(String mimeType) {
    175         ArrayList<String> array = null;
    176         for (int i=0; i<mMimeTypes.length; i++) {
    177             if (compareMimeTypes(mMimeTypes[i], mimeType)) {
    178                 if (array == null) {
    179                     array = new ArrayList<String>();
    180                 }
    181                 array.add(mMimeTypes[i]);
    182             }
    183         }
    184         if (array == null) {
    185             return null;
    186         }
    187         String[] rawArray = new String[array.size()];
    188         array.toArray(rawArray);
    189         return rawArray;
    190     }
    191 
    192     /**
    193      * Return the number of MIME types the clip is available in.
    194      */
    195     public int getMimeTypeCount() {
    196         return mMimeTypes.length;
    197     }
    198 
    199     /**
    200      * Return one of the possible clip MIME types.
    201      */
    202     public String getMimeType(int index) {
    203         return mMimeTypes[index];
    204     }
    205 
    206     /**
    207      * Retrieve extended data from the clip description.
    208      *
    209      * @return the bundle containing extended data previously set with
    210      * {@link #setExtras(PersistableBundle)}, or null if no extras have been set.
    211      *
    212      * @see #setExtras(PersistableBundle)
    213      */
    214     public PersistableBundle getExtras() {
    215         return mExtras;
    216     }
    217 
    218     /**
    219      * Add extended data to the clip description.
    220      *
    221      * @see #getExtras()
    222      */
    223     public void setExtras(PersistableBundle extras) {
    224         mExtras = new PersistableBundle(extras);
    225     }
    226 
    227     /** @hide */
    228     public void validate() {
    229         if (mMimeTypes == null) {
    230             throw new NullPointerException("null mime types");
    231         }
    232         if (mMimeTypes.length <= 0) {
    233             throw new IllegalArgumentException("must have at least 1 mime type");
    234         }
    235         for (int i=0; i<mMimeTypes.length; i++) {
    236             if (mMimeTypes[i] == null) {
    237                 throw new NullPointerException("mime type at " + i + " is null");
    238             }
    239         }
    240     }
    241 
    242     @Override
    243     public String toString() {
    244         StringBuilder b = new StringBuilder(128);
    245 
    246         b.append("ClipDescription { ");
    247         toShortString(b);
    248         b.append(" }");
    249 
    250         return b.toString();
    251     }
    252 
    253     /** @hide */
    254     public boolean toShortString(StringBuilder b) {
    255         boolean first = !toShortStringTypesOnly(b);
    256         if (mLabel != null) {
    257             if (!first) {
    258                 b.append(' ');
    259             }
    260             first = false;
    261             b.append('"');
    262             b.append(mLabel);
    263             b.append('"');
    264         }
    265         if (mExtras != null) {
    266             if (!first) {
    267                 b.append(' ');
    268             }
    269             first = false;
    270             b.append(mExtras.toString());
    271         }
    272         return !first;
    273     }
    274 
    275     /** @hide */
    276     public boolean toShortStringTypesOnly(StringBuilder b) {
    277         boolean first = true;
    278         for (int i=0; i<mMimeTypes.length; i++) {
    279             if (!first) {
    280                 b.append(' ');
    281             }
    282             first = false;
    283             b.append(mMimeTypes[i]);
    284         }
    285         return !first;
    286     }
    287 
    288     @Override
    289     public int describeContents() {
    290         return 0;
    291     }
    292 
    293     @Override
    294     public void writeToParcel(Parcel dest, int flags) {
    295         TextUtils.writeToParcel(mLabel, dest, flags);
    296         dest.writeStringArray(mMimeTypes);
    297         dest.writePersistableBundle(mExtras);
    298     }
    299 
    300     ClipDescription(Parcel in) {
    301         mLabel = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
    302         mMimeTypes = in.createStringArray();
    303         mExtras = in.readPersistableBundle();
    304     }
    305 
    306     public static final Parcelable.Creator<ClipDescription> CREATOR =
    307         new Parcelable.Creator<ClipDescription>() {
    308 
    309             public ClipDescription createFromParcel(Parcel source) {
    310                 return new ClipDescription(source);
    311             }
    312 
    313             public ClipDescription[] newArray(int size) {
    314                 return new ClipDescription[size];
    315             }
    316         };
    317 }
    318