Home | History | Annotate | Download | only in content
      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.content;
     18 
     19 import android.os.Parcel;
     20 import android.os.Parcelable;
     21 import android.text.TextUtils;
     22 
     23 import java.io.PrintWriter;
     24 import java.lang.Comparable;
     25 
     26 /**
     27  * Identifier for a specific application component
     28  * ({@link android.app.Activity}, {@link android.app.Service},
     29  * {@link android.content.BroadcastReceiver}, or
     30  * {@link android.content.ContentProvider}) that is available.  Two
     31  * pieces of information, encapsulated here, are required to identify
     32  * a component: the package (a String) it exists in, and the class (a String)
     33  * name inside of that package.
     34  *
     35  */
     36 public final class ComponentName implements Parcelable, Cloneable, Comparable<ComponentName> {
     37     private final String mPackage;
     38     private final String mClass;
     39 
     40     /**
     41      * Create a new component identifier where the class name may be specified
     42      * as either absolute or relative to the containing package.
     43      *
     44      * <p>Relative package names begin with a <code>'.'</code> character. For a package
     45      * <code>"com.example"</code> and class name <code>".app.MyActivity"</code> this method
     46      * will return a ComponentName with the package <code>"com.example"</code>and class name
     47      * <code>"com.example.app.MyActivity"</code>. Fully qualified class names are also
     48      * permitted.</p>
     49      *
     50      * @param pkg the name of the package the component exists in
     51      * @param cls the name of the class inside of <var>pkg</var> that implements
     52      *            the component
     53      * @return the new ComponentName
     54      */
     55     public static ComponentName createRelative(String pkg, String cls) {
     56         if (TextUtils.isEmpty(cls)) {
     57             throw new IllegalArgumentException("class name cannot be empty");
     58         }
     59 
     60         final String fullName;
     61         if (cls.charAt(0) == '.') {
     62             // Relative to the package. Prepend the package name.
     63             fullName = pkg + cls;
     64         } else {
     65             // Fully qualified package name.
     66             fullName = cls;
     67         }
     68         return new ComponentName(pkg, fullName);
     69     }
     70 
     71     /**
     72      * Create a new component identifier where the class name may be specified
     73      * as either absolute or relative to the containing package.
     74      *
     75      * <p>Relative package names begin with a <code>'.'</code> character. For a package
     76      * <code>"com.example"</code> and class name <code>".app.MyActivity"</code> this method
     77      * will return a ComponentName with the package <code>"com.example"</code>and class name
     78      * <code>"com.example.app.MyActivity"</code>. Fully qualified class names are also
     79      * permitted.</p>
     80      *
     81      * @param pkg a Context for the package implementing the component
     82      * @param cls the name of the class inside of <var>pkg</var> that implements
     83      *            the component
     84      * @return the new ComponentName
     85      */
     86     public static ComponentName createRelative(Context pkg, String cls) {
     87         return createRelative(pkg.getPackageName(), cls);
     88     }
     89 
     90     /**
     91      * Create a new component identifier.
     92      *
     93      * @param pkg The name of the package that the component exists in.  Can
     94      * not be null.
     95      * @param cls The name of the class inside of <var>pkg</var> that
     96      * implements the component.  Can not be null.
     97      */
     98     public ComponentName(String pkg, String cls) {
     99         if (pkg == null) throw new NullPointerException("package name is null");
    100         if (cls == null) throw new NullPointerException("class name is null");
    101         mPackage = pkg;
    102         mClass = cls;
    103     }
    104 
    105     /**
    106      * Create a new component identifier from a Context and class name.
    107      *
    108      * @param pkg A Context for the package implementing the component,
    109      * from which the actual package name will be retrieved.
    110      * @param cls The name of the class inside of <var>pkg</var> that
    111      * implements the component.
    112      */
    113     public ComponentName(Context pkg, String cls) {
    114         if (cls == null) throw new NullPointerException("class name is null");
    115         mPackage = pkg.getPackageName();
    116         mClass = cls;
    117     }
    118 
    119     /**
    120      * Create a new component identifier from a Context and Class object.
    121      *
    122      * @param pkg A Context for the package implementing the component, from
    123      * which the actual package name will be retrieved.
    124      * @param cls The Class object of the desired component, from which the
    125      * actual class name will be retrieved.
    126      */
    127     public ComponentName(Context pkg, Class<?> cls) {
    128         mPackage = pkg.getPackageName();
    129         mClass = cls.getName();
    130     }
    131 
    132     public ComponentName clone() {
    133         return new ComponentName(mPackage, mClass);
    134     }
    135 
    136     /**
    137      * Return the package name of this component.
    138      */
    139     public String getPackageName() {
    140         return mPackage;
    141     }
    142 
    143     /**
    144      * Return the class name of this component.
    145      */
    146     public String getClassName() {
    147         return mClass;
    148     }
    149 
    150     /**
    151      * Return the class name, either fully qualified or in a shortened form
    152      * (with a leading '.') if it is a suffix of the package.
    153      */
    154     public String getShortClassName() {
    155         if (mClass.startsWith(mPackage)) {
    156             int PN = mPackage.length();
    157             int CN = mClass.length();
    158             if (CN > PN && mClass.charAt(PN) == '.') {
    159                 return mClass.substring(PN, CN);
    160             }
    161         }
    162         return mClass;
    163     }
    164 
    165     private static void appendShortClassName(StringBuilder sb, String packageName,
    166             String className) {
    167         if (className.startsWith(packageName)) {
    168             int PN = packageName.length();
    169             int CN = className.length();
    170             if (CN > PN && className.charAt(PN) == '.') {
    171                 sb.append(className, PN, CN);
    172                 return;
    173             }
    174         }
    175         sb.append(className);
    176     }
    177 
    178     private static void printShortClassName(PrintWriter pw, String packageName,
    179             String className) {
    180         if (className.startsWith(packageName)) {
    181             int PN = packageName.length();
    182             int CN = className.length();
    183             if (CN > PN && className.charAt(PN) == '.') {
    184                 pw.write(className, PN, CN-PN);
    185                 return;
    186             }
    187         }
    188         pw.print(className);
    189     }
    190 
    191     /**
    192      * Return a String that unambiguously describes both the package and
    193      * class names contained in the ComponentName.  You can later recover
    194      * the ComponentName from this string through
    195      * {@link #unflattenFromString(String)}.
    196      *
    197      * @return Returns a new String holding the package and class names.  This
    198      * is represented as the package name, concatenated with a '/' and then the
    199      * class name.
    200      *
    201      * @see #unflattenFromString(String)
    202      */
    203     public String flattenToString() {
    204         return mPackage + "/" + mClass;
    205     }
    206 
    207     /**
    208      * The same as {@link #flattenToString()}, but abbreviates the class
    209      * name if it is a suffix of the package.  The result can still be used
    210      * with {@link #unflattenFromString(String)}.
    211      *
    212      * @return Returns a new String holding the package and class names.  This
    213      * is represented as the package name, concatenated with a '/' and then the
    214      * class name.
    215      *
    216      * @see #unflattenFromString(String)
    217      */
    218     public String flattenToShortString() {
    219         StringBuilder sb = new StringBuilder(mPackage.length() + mClass.length());
    220         appendShortString(sb, mPackage, mClass);
    221         return sb.toString();
    222     }
    223 
    224     /** @hide */
    225     public void appendShortString(StringBuilder sb) {
    226         appendShortString(sb, mPackage, mClass);
    227     }
    228 
    229     /** @hide */
    230     public static void appendShortString(StringBuilder sb, String packageName, String className) {
    231         sb.append(packageName).append('/');
    232         appendShortClassName(sb, packageName, className);
    233     }
    234 
    235     /** @hide */
    236     public static void printShortString(PrintWriter pw, String packageName, String className) {
    237         pw.print(packageName);
    238         pw.print('/');
    239         printShortClassName(pw, packageName, className);
    240     }
    241 
    242     /**
    243      * Recover a ComponentName from a String that was previously created with
    244      * {@link #flattenToString()}.  It splits the string at the first '/',
    245      * taking the part before as the package name and the part after as the
    246      * class name.  As a special convenience (to use, for example, when
    247      * parsing component names on the command line), if the '/' is immediately
    248      * followed by a '.' then the final class name will be the concatenation
    249      * of the package name with the string following the '/'.  Thus
    250      * "com.foo/.Blah" becomes package="com.foo" class="com.foo.Blah".
    251      *
    252      * @param str The String that was returned by flattenToString().
    253      * @return Returns a new ComponentName containing the package and class
    254      * names that were encoded in <var>str</var>
    255      *
    256      * @see #flattenToString()
    257      */
    258     public static ComponentName unflattenFromString(String str) {
    259         int sep = str.indexOf('/');
    260         if (sep < 0 || (sep+1) >= str.length()) {
    261             return null;
    262         }
    263         String pkg = str.substring(0, sep);
    264         String cls = str.substring(sep+1);
    265         if (cls.length() > 0 && cls.charAt(0) == '.') {
    266             cls = pkg + cls;
    267         }
    268         return new ComponentName(pkg, cls);
    269     }
    270 
    271     /**
    272      * Return string representation of this class without the class's name
    273      * as a prefix.
    274      */
    275     public String toShortString() {
    276         return "{" + mPackage + "/" + mClass + "}";
    277     }
    278 
    279     @Override
    280     public String toString() {
    281         return "ComponentInfo{" + mPackage + "/" + mClass + "}";
    282     }
    283 
    284     @Override
    285     public boolean equals(Object obj) {
    286         try {
    287             if (obj != null) {
    288                 ComponentName other = (ComponentName)obj;
    289                 // Note: no null checks, because mPackage and mClass can
    290                 // never be null.
    291                 return mPackage.equals(other.mPackage)
    292                         && mClass.equals(other.mClass);
    293             }
    294         } catch (ClassCastException e) {
    295         }
    296         return false;
    297     }
    298 
    299     @Override
    300     public int hashCode() {
    301         return mPackage.hashCode() + mClass.hashCode();
    302     }
    303 
    304     public int compareTo(ComponentName that) {
    305         int v;
    306         v = this.mPackage.compareTo(that.mPackage);
    307         if (v != 0) {
    308             return v;
    309         }
    310         return this.mClass.compareTo(that.mClass);
    311     }
    312 
    313     public int describeContents() {
    314         return 0;
    315     }
    316 
    317     public void writeToParcel(Parcel out, int flags) {
    318         out.writeString(mPackage);
    319         out.writeString(mClass);
    320     }
    321 
    322     /**
    323      * Write a ComponentName to a Parcel, handling null pointers.  Must be
    324      * read with {@link #readFromParcel(Parcel)}.
    325      *
    326      * @param c The ComponentName to be written.
    327      * @param out The Parcel in which the ComponentName will be placed.
    328      *
    329      * @see #readFromParcel(Parcel)
    330      */
    331     public static void writeToParcel(ComponentName c, Parcel out) {
    332         if (c != null) {
    333             c.writeToParcel(out, 0);
    334         } else {
    335             out.writeString(null);
    336         }
    337     }
    338 
    339     /**
    340      * Read a ComponentName from a Parcel that was previously written
    341      * with {@link #writeToParcel(ComponentName, Parcel)}, returning either
    342      * a null or new object as appropriate.
    343      *
    344      * @param in The Parcel from which to read the ComponentName
    345      * @return Returns a new ComponentName matching the previously written
    346      * object, or null if a null had been written.
    347      *
    348      * @see #writeToParcel(ComponentName, Parcel)
    349      */
    350     public static ComponentName readFromParcel(Parcel in) {
    351         String pkg = in.readString();
    352         return pkg != null ? new ComponentName(pkg, in) : null;
    353     }
    354 
    355     public static final Parcelable.Creator<ComponentName> CREATOR
    356             = new Parcelable.Creator<ComponentName>() {
    357         public ComponentName createFromParcel(Parcel in) {
    358             return new ComponentName(in);
    359         }
    360 
    361         public ComponentName[] newArray(int size) {
    362             return new ComponentName[size];
    363         }
    364     };
    365 
    366     /**
    367      * Instantiate a new ComponentName from the data in a Parcel that was
    368      * previously written with {@link #writeToParcel(Parcel, int)}.  Note that you
    369      * must not use this with data written by
    370      * {@link #writeToParcel(ComponentName, Parcel)} since it is not possible
    371      * to handle a null ComponentObject here.
    372      *
    373      * @param in The Parcel containing the previously written ComponentName,
    374      * positioned at the location in the buffer where it was written.
    375      */
    376     public ComponentName(Parcel in) {
    377         mPackage = in.readString();
    378         if (mPackage == null) throw new NullPointerException(
    379                 "package name is null");
    380         mClass = in.readString();
    381         if (mClass == null) throw new NullPointerException(
    382                 "class name is null");
    383     }
    384 
    385     private ComponentName(String pkg, Parcel in) {
    386         mPackage = pkg;
    387         mClass = in.readString();
    388     }
    389 }
    390