blob: e6ffe8b4fe8682b287320feeab5b2057cecd4d9e [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;
Mathew Inwood5c0d3542018-08-14 13:54:31 +010021import android.annotation.UnsupportedAppUsage;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080022import android.os.Parcel;
23import android.os.Parcelable;
Adam Powellecee3222015-04-14 15:20:16 -070024import android.text.TextUtils;
Kweku Adams93304b62017-09-20 17:03:00 -070025import android.util.proto.ProtoOutputStream;
Dianne Hackborn6d8dfbd2013-09-23 17:38:51 -070026
27import java.io.PrintWriter;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080028
29/**
30 * Identifier for a specific application component
31 * ({@link android.app.Activity}, {@link android.app.Service},
32 * {@link android.content.BroadcastReceiver}, or
33 * {@link android.content.ContentProvider}) that is available. Two
34 * pieces of information, encapsulated here, are required to identify
35 * a component: the package (a String) it exists in, and the class (a String)
36 * name inside of that package.
Kweku Adams93304b62017-09-20 17:03:00 -070037 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080038 */
Joe Onoratoedc649a2010-02-08 12:40:45 -080039public final class ComponentName implements Parcelable, Cloneable, Comparable<ComponentName> {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080040 private final String mPackage;
41 private final String mClass;
42
43 /**
Adam Powellecee3222015-04-14 15:20:16 -070044 * Create a new component identifier where the class name may be specified
45 * as either absolute or relative to the containing package.
46 *
47 * <p>Relative package names begin with a <code>'.'</code> character. For a package
48 * <code>"com.example"</code> and class name <code>".app.MyActivity"</code> this method
49 * will return a ComponentName with the package <code>"com.example"</code>and class name
50 * <code>"com.example.app.MyActivity"</code>. Fully qualified class names are also
51 * permitted.</p>
52 *
53 * @param pkg the name of the package the component exists in
54 * @param cls the name of the class inside of <var>pkg</var> that implements
55 * the component
56 * @return the new ComponentName
57 */
Jeff Sharkey30e06bb2017-04-24 11:18:03 -060058 public static @NonNull ComponentName createRelative(@NonNull String pkg, @NonNull String cls) {
Adam Powellecee3222015-04-14 15:20:16 -070059 if (TextUtils.isEmpty(cls)) {
60 throw new IllegalArgumentException("class name cannot be empty");
61 }
62
63 final String fullName;
64 if (cls.charAt(0) == '.') {
65 // Relative to the package. Prepend the package name.
66 fullName = pkg + cls;
67 } else {
68 // Fully qualified package name.
69 fullName = cls;
70 }
71 return new ComponentName(pkg, fullName);
72 }
73
74 /**
75 * Create a new component identifier where the class name may be specified
76 * as either absolute or relative to the containing package.
77 *
78 * <p>Relative package names begin with a <code>'.'</code> character. For a package
79 * <code>"com.example"</code> and class name <code>".app.MyActivity"</code> this method
80 * will return a ComponentName with the package <code>"com.example"</code>and class name
81 * <code>"com.example.app.MyActivity"</code>. Fully qualified class names are also
82 * permitted.</p>
83 *
84 * @param pkg a Context for the package implementing the component
85 * @param cls the name of the class inside of <var>pkg</var> that implements
86 * the component
87 * @return the new ComponentName
88 */
Jeff Sharkey30e06bb2017-04-24 11:18:03 -060089 public static @NonNull ComponentName createRelative(@NonNull Context pkg, @NonNull String cls) {
Adam Powellecee3222015-04-14 15:20:16 -070090 return createRelative(pkg.getPackageName(), cls);
91 }
92
93 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080094 * Create a new component identifier.
Kweku Adams93304b62017-09-20 17:03:00 -070095 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080096 * @param pkg The name of the package that the component exists in. Can
97 * not be null.
98 * @param cls The name of the class inside of <var>pkg</var> that
99 * implements the component. Can not be null.
100 */
Jeff Sharkey30e06bb2017-04-24 11:18:03 -0600101 public ComponentName(@NonNull String pkg, @NonNull String cls) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800102 if (pkg == null) throw new NullPointerException("package name is null");
103 if (cls == null) throw new NullPointerException("class name is null");
104 mPackage = pkg;
105 mClass = cls;
106 }
107
108 /**
109 * Create a new component identifier from a Context and class name.
Kweku Adams93304b62017-09-20 17:03:00 -0700110 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800111 * @param pkg A Context for the package implementing the component,
112 * from which the actual package name will be retrieved.
113 * @param cls The name of the class inside of <var>pkg</var> that
114 * implements the component.
115 */
Jeff Sharkey30e06bb2017-04-24 11:18:03 -0600116 public ComponentName(@NonNull Context pkg, @NonNull String cls) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800117 if (cls == null) throw new NullPointerException("class name is null");
118 mPackage = pkg.getPackageName();
119 mClass = cls;
120 }
121
122 /**
123 * Create a new component identifier from a Context and Class object.
Kweku Adams93304b62017-09-20 17:03:00 -0700124 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800125 * @param pkg A Context for the package implementing the component, from
126 * which the actual package name will be retrieved.
127 * @param cls The Class object of the desired component, from which the
128 * actual class name will be retrieved.
129 */
Jeff Sharkey30e06bb2017-04-24 11:18:03 -0600130 public ComponentName(@NonNull Context pkg, @NonNull Class<?> cls) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800131 mPackage = pkg.getPackageName();
132 mClass = cls.getName();
133 }
134
Joe Onoratoedc649a2010-02-08 12:40:45 -0800135 public ComponentName clone() {
136 return new ComponentName(mPackage, mClass);
137 }
138
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800139 /**
140 * Return the package name of this component.
141 */
Jeff Sharkey30e06bb2017-04-24 11:18:03 -0600142 public @NonNull String getPackageName() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800143 return mPackage;
144 }
Kweku Adams93304b62017-09-20 17:03:00 -0700145
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800146 /**
147 * Return the class name of this component.
148 */
Jeff Sharkey30e06bb2017-04-24 11:18:03 -0600149 public @NonNull String getClassName() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800150 return mClass;
151 }
Kweku Adams93304b62017-09-20 17:03:00 -0700152
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800153 /**
154 * Return the class name, either fully qualified or in a shortened form
155 * (with a leading '.') if it is a suffix of the package.
156 */
157 public String getShortClassName() {
158 if (mClass.startsWith(mPackage)) {
159 int PN = mPackage.length();
160 int CN = mClass.length();
161 if (CN > PN && mClass.charAt(PN) == '.') {
162 return mClass.substring(PN, CN);
163 }
164 }
165 return mClass;
166 }
Kweku Adams93304b62017-09-20 17:03:00 -0700167
Dianne Hackborn6d8dfbd2013-09-23 17:38:51 -0700168 private static void appendShortClassName(StringBuilder sb, String packageName,
169 String className) {
170 if (className.startsWith(packageName)) {
171 int PN = packageName.length();
172 int CN = className.length();
173 if (CN > PN && className.charAt(PN) == '.') {
174 sb.append(className, PN, CN);
175 return;
176 }
177 }
178 sb.append(className);
179 }
180
181 private static void printShortClassName(PrintWriter pw, String packageName,
182 String className) {
183 if (className.startsWith(packageName)) {
184 int PN = packageName.length();
185 int CN = className.length();
186 if (CN > PN && className.charAt(PN) == '.') {
187 pw.write(className, PN, CN-PN);
188 return;
189 }
190 }
191 pw.print(className);
192 }
193
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800194 /**
Felipe Lemeaa5088e2018-12-10 14:53:58 -0800195 * Helper to get {@link #flattenToShortString()} in a {@link ComponentName} reference that can
196 * be {@code null}.
197 *
198 * @hide
199 */
200 @Nullable
201 public static String flattenToShortString(@Nullable ComponentName componentName) {
202 return componentName == null ? null : componentName.flattenToShortString();
203 }
204
205 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800206 * Return a String that unambiguously describes both the package and
207 * class names contained in the ComponentName. You can later recover
208 * the ComponentName from this string through
209 * {@link #unflattenFromString(String)}.
Kweku Adams93304b62017-09-20 17:03:00 -0700210 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800211 * @return Returns a new String holding the package and class names. This
212 * is represented as the package name, concatenated with a '/' and then the
213 * class name.
Kweku Adams93304b62017-09-20 17:03:00 -0700214 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800215 * @see #unflattenFromString(String)
216 */
Jeff Sharkey30e06bb2017-04-24 11:18:03 -0600217 public @NonNull String flattenToString() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800218 return mPackage + "/" + mClass;
219 }
Kweku Adams93304b62017-09-20 17:03:00 -0700220
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800221 /**
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800222 * The same as {@link #flattenToString()}, but abbreviates the class
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800223 * name if it is a suffix of the package. The result can still be used
224 * with {@link #unflattenFromString(String)}.
Kweku Adams93304b62017-09-20 17:03:00 -0700225 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800226 * @return Returns a new String holding the package and class names. This
227 * is represented as the package name, concatenated with a '/' and then the
228 * class name.
Kweku Adams93304b62017-09-20 17:03:00 -0700229 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800230 * @see #unflattenFromString(String)
231 */
Jeff Sharkey30e06bb2017-04-24 11:18:03 -0600232 public @NonNull String flattenToShortString() {
Dianne Hackborn6d8dfbd2013-09-23 17:38:51 -0700233 StringBuilder sb = new StringBuilder(mPackage.length() + mClass.length());
234 appendShortString(sb, mPackage, mClass);
235 return sb.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800236 }
Dianne Hackborn6d8dfbd2013-09-23 17:38:51 -0700237
238 /** @hide */
239 public void appendShortString(StringBuilder sb) {
240 appendShortString(sb, mPackage, mClass);
241 }
242
243 /** @hide */
Mathew Inwood5c0d3542018-08-14 13:54:31 +0100244 @UnsupportedAppUsage
Dianne Hackborn6d8dfbd2013-09-23 17:38:51 -0700245 public static void appendShortString(StringBuilder sb, String packageName, String className) {
246 sb.append(packageName).append('/');
247 appendShortClassName(sb, packageName, className);
248 }
249
250 /** @hide */
Mathew Inwood5c0d3542018-08-14 13:54:31 +0100251 @UnsupportedAppUsage
Dianne Hackborn6d8dfbd2013-09-23 17:38:51 -0700252 public static void printShortString(PrintWriter pw, String packageName, String className) {
253 pw.print(packageName);
254 pw.print('/');
255 printShortClassName(pw, packageName, className);
256 }
257
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800258 /**
259 * Recover a ComponentName from a String that was previously created with
260 * {@link #flattenToString()}. It splits the string at the first '/',
261 * taking the part before as the package name and the part after as the
262 * class name. As a special convenience (to use, for example, when
263 * parsing component names on the command line), if the '/' is immediately
264 * followed by a '.' then the final class name will be the concatenation
265 * of the package name with the string following the '/'. Thus
266 * "com.foo/.Blah" becomes package="com.foo" class="com.foo.Blah".
Kweku Adams93304b62017-09-20 17:03:00 -0700267 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800268 * @param str The String that was returned by flattenToString().
269 * @return Returns a new ComponentName containing the package and class
270 * names that were encoded in <var>str</var>
Kweku Adams93304b62017-09-20 17:03:00 -0700271 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800272 * @see #flattenToString()
273 */
Jeff Sharkey30e06bb2017-04-24 11:18:03 -0600274 public static @Nullable ComponentName unflattenFromString(@NonNull String str) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800275 int sep = str.indexOf('/');
276 if (sep < 0 || (sep+1) >= str.length()) {
277 return null;
278 }
279 String pkg = str.substring(0, sep);
280 String cls = str.substring(sep+1);
281 if (cls.length() > 0 && cls.charAt(0) == '.') {
282 cls = pkg + cls;
283 }
284 return new ComponentName(pkg, cls);
285 }
Kweku Adams93304b62017-09-20 17:03:00 -0700286
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800287 /**
288 * Return string representation of this class without the class's name
289 * as a prefix.
290 */
291 public String toShortString() {
292 return "{" + mPackage + "/" + mClass + "}";
293 }
294
295 @Override
296 public String toString() {
297 return "ComponentInfo{" + mPackage + "/" + mClass + "}";
298 }
299
Kweku Adams93304b62017-09-20 17:03:00 -0700300 /** Put this here so that individual services don't have to reimplement this. @hide */
Kweku Adams85f2fbc2017-12-18 12:04:12 -0800301 public void writeToProto(ProtoOutputStream proto, long fieldId) {
302 final long token = proto.start(fieldId);
Kweku Adams93304b62017-09-20 17:03:00 -0700303 proto.write(ComponentNameProto.PACKAGE_NAME, mPackage);
304 proto.write(ComponentNameProto.CLASS_NAME, mClass);
Kweku Adams85f2fbc2017-12-18 12:04:12 -0800305 proto.end(token);
Kweku Adams93304b62017-09-20 17:03:00 -0700306 }
307
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800308 @Override
309 public boolean equals(Object obj) {
310 try {
311 if (obj != null) {
312 ComponentName other = (ComponentName)obj;
313 // Note: no null checks, because mPackage and mClass can
314 // never be null.
315 return mPackage.equals(other.mPackage)
316 && mClass.equals(other.mClass);
317 }
318 } catch (ClassCastException e) {
319 }
320 return false;
321 }
322
323 @Override
324 public int hashCode() {
325 return mPackage.hashCode() + mClass.hashCode();
326 }
Joe Onorato6b61d412009-05-12 14:42:58 -0400327
328 public int compareTo(ComponentName that) {
329 int v;
330 v = this.mPackage.compareTo(that.mPackage);
331 if (v != 0) {
332 return v;
333 }
334 return this.mClass.compareTo(that.mClass);
335 }
Kweku Adams93304b62017-09-20 17:03:00 -0700336
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800337 public int describeContents() {
338 return 0;
339 }
340
341 public void writeToParcel(Parcel out, int flags) {
342 out.writeString(mPackage);
343 out.writeString(mClass);
344 }
345
346 /**
347 * Write a ComponentName to a Parcel, handling null pointers. Must be
348 * read with {@link #readFromParcel(Parcel)}.
Kweku Adams93304b62017-09-20 17:03:00 -0700349 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800350 * @param c The ComponentName to be written.
351 * @param out The Parcel in which the ComponentName will be placed.
Kweku Adams93304b62017-09-20 17:03:00 -0700352 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800353 * @see #readFromParcel(Parcel)
354 */
355 public static void writeToParcel(ComponentName c, Parcel out) {
356 if (c != null) {
357 c.writeToParcel(out, 0);
358 } else {
359 out.writeString(null);
360 }
361 }
Kweku Adams93304b62017-09-20 17:03:00 -0700362
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800363 /**
364 * Read a ComponentName from a Parcel that was previously written
365 * with {@link #writeToParcel(ComponentName, Parcel)}, returning either
366 * a null or new object as appropriate.
Kweku Adams93304b62017-09-20 17:03:00 -0700367 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800368 * @param in The Parcel from which to read the ComponentName
369 * @return Returns a new ComponentName matching the previously written
370 * object, or null if a null had been written.
Kweku Adams93304b62017-09-20 17:03:00 -0700371 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800372 * @see #writeToParcel(ComponentName, Parcel)
373 */
374 public static ComponentName readFromParcel(Parcel in) {
375 String pkg = in.readString();
376 return pkg != null ? new ComponentName(pkg, in) : null;
377 }
Kweku Adams93304b62017-09-20 17:03:00 -0700378
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800379 public static final Parcelable.Creator<ComponentName> CREATOR
380 = new Parcelable.Creator<ComponentName>() {
381 public ComponentName createFromParcel(Parcel in) {
382 return new ComponentName(in);
383 }
384
385 public ComponentName[] newArray(int size) {
386 return new ComponentName[size];
387 }
388 };
389
390 /**
391 * Instantiate a new ComponentName from the data in a Parcel that was
392 * previously written with {@link #writeToParcel(Parcel, int)}. Note that you
393 * must not use this with data written by
394 * {@link #writeToParcel(ComponentName, Parcel)} since it is not possible
395 * to handle a null ComponentObject here.
Kweku Adams93304b62017-09-20 17:03:00 -0700396 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800397 * @param in The Parcel containing the previously written ComponentName,
398 * positioned at the location in the buffer where it was written.
399 */
400 public ComponentName(Parcel in) {
401 mPackage = in.readString();
402 if (mPackage == null) throw new NullPointerException(
403 "package name is null");
404 mClass = in.readString();
405 if (mClass == null) throw new NullPointerException(
406 "class name is null");
407 }
408
409 private ComponentName(String pkg, Parcel in) {
410 mPackage = pkg;
411 mClass = in.readString();
412 }
Makoto Onuki0b575a32018-04-16 14:33:59 -0700413
414 /**
415 * Interface for classes associated with a component name.
416 * @hide
417 */
418 @FunctionalInterface
419 public interface WithComponentName {
420 /** Return the associated component name. */
421 ComponentName getComponentName();
422 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800423}