blob: fc5853353ce6eef5df2de7a05f75b904156cb20d [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
Jeff Sharkey30e06bb2017-04-24 11:18:03 -060019import android.annotation.NonNull;
20import android.annotation.Nullable;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080021import android.os.Parcel;
22import android.os.Parcelable;
Adam Powellecee3222015-04-14 15:20:16 -070023import android.text.TextUtils;
Kweku Adams93304b62017-09-20 17:03:00 -070024import android.util.proto.ProtoOutputStream;
Dianne Hackborn6d8dfbd2013-09-23 17:38:51 -070025
26import java.io.PrintWriter;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080027
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.
Kweku Adams93304b62017-09-20 17:03:00 -070036 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080037 */
Joe Onoratoedc649a2010-02-08 12:40:45 -080038public final class ComponentName implements Parcelable, Cloneable, Comparable<ComponentName> {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039 private final String mPackage;
40 private final String mClass;
41
42 /**
Adam Powellecee3222015-04-14 15:20:16 -070043 * 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 */
Jeff Sharkey30e06bb2017-04-24 11:18:03 -060057 public static @NonNull ComponentName createRelative(@NonNull String pkg, @NonNull String cls) {
Adam Powellecee3222015-04-14 15:20:16 -070058 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 */
Jeff Sharkey30e06bb2017-04-24 11:18:03 -060088 public static @NonNull ComponentName createRelative(@NonNull Context pkg, @NonNull String cls) {
Adam Powellecee3222015-04-14 15:20:16 -070089 return createRelative(pkg.getPackageName(), cls);
90 }
91
92 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080093 * Create a new component identifier.
Kweku Adams93304b62017-09-20 17:03:00 -070094 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080095 * @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 */
Jeff Sharkey30e06bb2017-04-24 11:18:03 -0600100 public ComponentName(@NonNull String pkg, @NonNull String cls) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800101 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.
Kweku Adams93304b62017-09-20 17:03:00 -0700109 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800110 * @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 */
Jeff Sharkey30e06bb2017-04-24 11:18:03 -0600115 public ComponentName(@NonNull Context pkg, @NonNull String cls) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800116 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.
Kweku Adams93304b62017-09-20 17:03:00 -0700123 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800124 * @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 */
Jeff Sharkey30e06bb2017-04-24 11:18:03 -0600129 public ComponentName(@NonNull Context pkg, @NonNull Class<?> cls) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800130 mPackage = pkg.getPackageName();
131 mClass = cls.getName();
132 }
133
Joe Onoratoedc649a2010-02-08 12:40:45 -0800134 public ComponentName clone() {
135 return new ComponentName(mPackage, mClass);
136 }
137
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800138 /**
139 * Return the package name of this component.
140 */
Jeff Sharkey30e06bb2017-04-24 11:18:03 -0600141 public @NonNull String getPackageName() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800142 return mPackage;
143 }
Kweku Adams93304b62017-09-20 17:03:00 -0700144
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800145 /**
146 * Return the class name of this component.
147 */
Jeff Sharkey30e06bb2017-04-24 11:18:03 -0600148 public @NonNull String getClassName() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800149 return mClass;
150 }
Kweku Adams93304b62017-09-20 17:03:00 -0700151
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800152 /**
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 */
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 }
Kweku Adams93304b62017-09-20 17:03:00 -0700166
Dianne Hackborn6d8dfbd2013-09-23 17:38:51 -0700167 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
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
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800193 /**
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)}.
Kweku Adams93304b62017-09-20 17:03:00 -0700198 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800199 * @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.
Kweku Adams93304b62017-09-20 17:03:00 -0700202 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800203 * @see #unflattenFromString(String)
204 */
Jeff Sharkey30e06bb2017-04-24 11:18:03 -0600205 public @NonNull String flattenToString() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800206 return mPackage + "/" + mClass;
207 }
Kweku Adams93304b62017-09-20 17:03:00 -0700208
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800209 /**
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800210 * The same as {@link #flattenToString()}, but abbreviates the class
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800211 * name if it is a suffix of the package. The result can still be used
212 * with {@link #unflattenFromString(String)}.
Kweku Adams93304b62017-09-20 17:03:00 -0700213 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800214 * @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.
Kweku Adams93304b62017-09-20 17:03:00 -0700217 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800218 * @see #unflattenFromString(String)
219 */
Jeff Sharkey30e06bb2017-04-24 11:18:03 -0600220 public @NonNull String flattenToShortString() {
Dianne Hackborn6d8dfbd2013-09-23 17:38:51 -0700221 StringBuilder sb = new StringBuilder(mPackage.length() + mClass.length());
222 appendShortString(sb, mPackage, mClass);
223 return sb.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800224 }
Dianne Hackborn6d8dfbd2013-09-23 17:38:51 -0700225
226 /** @hide */
227 public void appendShortString(StringBuilder sb) {
228 appendShortString(sb, mPackage, mClass);
229 }
230
231 /** @hide */
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 */
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
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800244 /**
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".
Kweku Adams93304b62017-09-20 17:03:00 -0700253 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800254 * @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>
Kweku Adams93304b62017-09-20 17:03:00 -0700257 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800258 * @see #flattenToString()
259 */
Jeff Sharkey30e06bb2017-04-24 11:18:03 -0600260 public static @Nullable ComponentName unflattenFromString(@NonNull String str) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800261 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 }
Kweku Adams93304b62017-09-20 17:03:00 -0700272
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800273 /**
274 * Return string representation of this class without the class's name
275 * as a prefix.
276 */
277 public String toShortString() {
278 return "{" + mPackage + "/" + mClass + "}";
279 }
280
281 @Override
282 public String toString() {
283 return "ComponentInfo{" + mPackage + "/" + mClass + "}";
284 }
285
Kweku Adams93304b62017-09-20 17:03:00 -0700286 /** Put this here so that individual services don't have to reimplement this. @hide */
Kweku Adams85f2fbc2017-12-18 12:04:12 -0800287 public void writeToProto(ProtoOutputStream proto, long fieldId) {
288 final long token = proto.start(fieldId);
Kweku Adams93304b62017-09-20 17:03:00 -0700289 proto.write(ComponentNameProto.PACKAGE_NAME, mPackage);
290 proto.write(ComponentNameProto.CLASS_NAME, mClass);
Kweku Adams85f2fbc2017-12-18 12:04:12 -0800291 proto.end(token);
Kweku Adams93304b62017-09-20 17:03:00 -0700292 }
293
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800294 @Override
295 public boolean equals(Object obj) {
296 try {
297 if (obj != null) {
298 ComponentName other = (ComponentName)obj;
299 // Note: no null checks, because mPackage and mClass can
300 // never be null.
301 return mPackage.equals(other.mPackage)
302 && mClass.equals(other.mClass);
303 }
304 } catch (ClassCastException e) {
305 }
306 return false;
307 }
308
309 @Override
310 public int hashCode() {
311 return mPackage.hashCode() + mClass.hashCode();
312 }
Joe Onorato6b61d412009-05-12 14:42:58 -0400313
314 public int compareTo(ComponentName that) {
315 int v;
316 v = this.mPackage.compareTo(that.mPackage);
317 if (v != 0) {
318 return v;
319 }
320 return this.mClass.compareTo(that.mClass);
321 }
Kweku Adams93304b62017-09-20 17:03:00 -0700322
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800323 public int describeContents() {
324 return 0;
325 }
326
327 public void writeToParcel(Parcel out, int flags) {
328 out.writeString(mPackage);
329 out.writeString(mClass);
330 }
331
332 /**
333 * Write a ComponentName to a Parcel, handling null pointers. Must be
334 * read with {@link #readFromParcel(Parcel)}.
Kweku Adams93304b62017-09-20 17:03:00 -0700335 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800336 * @param c The ComponentName to be written.
337 * @param out The Parcel in which the ComponentName will be placed.
Kweku Adams93304b62017-09-20 17:03:00 -0700338 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800339 * @see #readFromParcel(Parcel)
340 */
341 public static void writeToParcel(ComponentName c, Parcel out) {
342 if (c != null) {
343 c.writeToParcel(out, 0);
344 } else {
345 out.writeString(null);
346 }
347 }
Kweku Adams93304b62017-09-20 17:03:00 -0700348
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800349 /**
350 * Read a ComponentName from a Parcel that was previously written
351 * with {@link #writeToParcel(ComponentName, Parcel)}, returning either
352 * a null or new object as appropriate.
Kweku Adams93304b62017-09-20 17:03:00 -0700353 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800354 * @param in The Parcel from which to read the ComponentName
355 * @return Returns a new ComponentName matching the previously written
356 * object, or null if a null had been written.
Kweku Adams93304b62017-09-20 17:03:00 -0700357 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800358 * @see #writeToParcel(ComponentName, Parcel)
359 */
360 public static ComponentName readFromParcel(Parcel in) {
361 String pkg = in.readString();
362 return pkg != null ? new ComponentName(pkg, in) : null;
363 }
Kweku Adams93304b62017-09-20 17:03:00 -0700364
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800365 public static final Parcelable.Creator<ComponentName> CREATOR
366 = new Parcelable.Creator<ComponentName>() {
367 public ComponentName createFromParcel(Parcel in) {
368 return new ComponentName(in);
369 }
370
371 public ComponentName[] newArray(int size) {
372 return new ComponentName[size];
373 }
374 };
375
376 /**
377 * Instantiate a new ComponentName from the data in a Parcel that was
378 * previously written with {@link #writeToParcel(Parcel, int)}. Note that you
379 * must not use this with data written by
380 * {@link #writeToParcel(ComponentName, Parcel)} since it is not possible
381 * to handle a null ComponentObject here.
Kweku Adams93304b62017-09-20 17:03:00 -0700382 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800383 * @param in The Parcel containing the previously written ComponentName,
384 * positioned at the location in the buffer where it was written.
385 */
386 public ComponentName(Parcel in) {
387 mPackage = in.readString();
388 if (mPackage == null) throw new NullPointerException(
389 "package name is null");
390 mClass = in.readString();
391 if (mClass == null) throw new NullPointerException(
392 "class name is null");
393 }
394
395 private ComponentName(String pkg, Parcel in) {
396 mPackage = pkg;
397 mClass = in.readString();
398 }
Makoto Onuki0b575a32018-04-16 14:33:59 -0700399
400 /**
401 * Interface for classes associated with a component name.
402 * @hide
403 */
404 @FunctionalInterface
405 public interface WithComponentName {
406 /** Return the associated component name. */
407 ComponentName getComponentName();
408 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800409}