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