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