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