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 */ createRelative(String pkg, String cls)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 */ createRelative(Context pkg, String cls)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 */ ComponentName(String pkg, String cls)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 */ ComponentName(Context pkg, String cls)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 */ ComponentName(Context pkg, Class<?> cls)127 public ComponentName(Context pkg, Class<?> cls) { 128 mPackage = pkg.getPackageName(); 129 mClass = cls.getName(); 130 } 131 clone()132 public ComponentName clone() { 133 return new ComponentName(mPackage, mClass); 134 } 135 136 /** 137 * Return the package name of this component. 138 */ getPackageName()139 public String getPackageName() { 140 return mPackage; 141 } 142 143 /** 144 * Return the class name of this component. 145 */ getClassName()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 */ getShortClassName()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 appendShortClassName(StringBuilder sb, String packageName, String className)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 printShortClassName(PrintWriter pw, String packageName, String className)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 */ flattenToString()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 */ flattenToShortString()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 */ appendShortString(StringBuilder sb)225 public void appendShortString(StringBuilder sb) { 226 appendShortString(sb, mPackage, mClass); 227 } 228 229 /** @hide */ appendShortString(StringBuilder sb, String packageName, String className)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 */ printShortString(PrintWriter pw, String packageName, String className)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 */ unflattenFromString(String str)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 */ toShortString()275 public String toShortString() { 276 return "{" + mPackage + "/" + mClass + "}"; 277 } 278 279 @Override toString()280 public String toString() { 281 return "ComponentInfo{" + mPackage + "/" + mClass + "}"; 282 } 283 284 @Override equals(Object obj)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 hashCode()300 public int hashCode() { 301 return mPackage.hashCode() + mClass.hashCode(); 302 } 303 compareTo(ComponentName that)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 describeContents()313 public int describeContents() { 314 return 0; 315 } 316 writeToParcel(Parcel out, int flags)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 */ writeToParcel(ComponentName c, Parcel out)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 */ readFromParcel(Parcel in)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 */ ComponentName(Parcel in)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 ComponentName(String pkg, Parcel in)385 private ComponentName(String pkg, Parcel in) { 386 mPackage = pkg; 387 mClass = in.readString(); 388 } 389 } 390