blob: 8aeb22dddd1e26033ad4b1be99351cad55043934 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
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
17package android.content;
18
19import android.os.Parcel;
20import android.os.Parcelable;
Adam Powellecee3222015-04-14 15:20:16 -070021import android.text.TextUtils;
Dianne Hackborn6d8dfbd2013-09-23 17:38:51 -070022
23import java.io.PrintWriter;
Joe Onorato6b61d412009-05-12 14:42:58 -040024import java.lang.Comparable;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080025
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 */
Joe Onoratoedc649a2010-02-08 12:40:45 -080036public final class ComponentName implements Parcelable, Cloneable, Comparable<ComponentName> {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080037 private final String mPackage;
38 private final String mClass;
39
40 /**
Adam Powellecee3222015-04-14 15:20:16 -070041 * 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 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080091 * 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
Joe Onoratoedc649a2010-02-08 12:40:45 -0800132 public ComponentName clone() {
133 return new ComponentName(mPackage, mClass);
134 }
135
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800136 /**
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
Dianne Hackborn6d8dfbd2013-09-23 17:38:51 -0700165 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
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800191 /**
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 /**
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800208 * The same as {@link #flattenToString()}, but abbreviates the class
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800209 * 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() {
Dianne Hackborn6d8dfbd2013-09-23 17:38:51 -0700219 StringBuilder sb = new StringBuilder(mPackage.length() + mClass.length());
220 appendShortString(sb, mPackage, mClass);
221 return sb.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800222 }
Dianne Hackborn6d8dfbd2013-09-23 17:38:51 -0700223
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
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800242 /**
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 }
Joe Onorato6b61d412009-05-12 14:42:58 -0400303
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 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800312
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}