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 */ ComponentName(String pkg, String cls)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 */ ComponentName(Context pkg, String cls)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 */ ComponentName(Context pkg, Class<?> cls)76 public ComponentName(Context pkg, Class<?> cls) { 77 mPackage = pkg.getPackageName(); 78 mClass = cls.getName(); 79 } 80 clone()81 public ComponentName clone() { 82 return new ComponentName(mPackage, mClass); 83 } 84 85 /** 86 * Return the package name of this component. 87 */ getPackageName()88 public String getPackageName() { 89 return mPackage; 90 } 91 92 /** 93 * Return the class name of this component. 94 */ getClassName()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 */ getShortClassName()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 appendShortClassName(StringBuilder sb, String packageName, String className)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 printShortClassName(PrintWriter pw, String packageName, String className)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 */ flattenToString()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 */ flattenToShortString()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 */ appendShortString(StringBuilder sb)174 public void appendShortString(StringBuilder sb) { 175 appendShortString(sb, mPackage, mClass); 176 } 177 178 /** @hide */ appendShortString(StringBuilder sb, String packageName, String className)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 */ printShortString(PrintWriter pw, String packageName, String className)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 */ unflattenFromString(String str)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 */ toShortString()224 public String toShortString() { 225 return "{" + mPackage + "/" + mClass + "}"; 226 } 227 228 @Override toString()229 public String toString() { 230 return "ComponentInfo{" + mPackage + "/" + mClass + "}"; 231 } 232 233 @Override equals(Object obj)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 hashCode()249 public int hashCode() { 250 return mPackage.hashCode() + mClass.hashCode(); 251 } 252 compareTo(ComponentName that)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 describeContents()262 public int describeContents() { 263 return 0; 264 } 265 writeToParcel(Parcel out, int flags)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 */ writeToParcel(ComponentName c, Parcel out)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 */ readFromParcel(Parcel in)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 */ ComponentName(Parcel in)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 ComponentName(String pkg, Parcel in)334 private ComponentName(String pkg, Parcel in) { 335 mPackage = pkg; 336 mClass = in.readString(); 337 } 338 } 339