• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2007 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.pm;
18 
19 import android.annotation.SystemApi;
20 import android.compat.annotation.UnsupportedAppUsage;
21 import android.content.ComponentName;
22 import android.content.IntentFilter;
23 import android.graphics.drawable.Drawable;
24 import android.os.Parcel;
25 import android.os.Parcelable;
26 import android.os.UserHandle;
27 import android.text.TextUtils;
28 import android.util.Printer;
29 import android.util.Slog;
30 
31 import java.text.Collator;
32 import java.util.Comparator;
33 
34 /**
35  * Information that is returned from resolving an intent
36  * against an IntentFilter. This partially corresponds to
37  * information collected from the AndroidManifest.xml's
38  * <intent> tags.
39  */
40 public class ResolveInfo implements Parcelable {
41     private static final String TAG = "ResolveInfo";
42     private static final String INTENT_FORWARDER_ACTIVITY =
43             "com.android.internal.app.IntentForwarderActivity";
44 
45     /**
46      * The activity or broadcast receiver that corresponds to this resolution
47      * match, if this resolution is for an activity or broadcast receiver.
48      * Exactly one of {@link #activityInfo}, {@link #serviceInfo}, or
49      * {@link #providerInfo} will be non-null.
50      */
51     public ActivityInfo activityInfo;
52 
53     /**
54      * The service that corresponds to this resolution match, if this resolution
55      * is for a service. Exactly one of {@link #activityInfo},
56      * {@link #serviceInfo}, or {@link #providerInfo} will be non-null.
57      */
58     public ServiceInfo serviceInfo;
59 
60     /**
61      * The provider that corresponds to this resolution match, if this
62      * resolution is for a provider. Exactly one of {@link #activityInfo},
63      * {@link #serviceInfo}, or {@link #providerInfo} will be non-null.
64      */
65     public ProviderInfo providerInfo;
66 
67     /**
68      * An auxiliary response that may modify the resolved information. This is
69      * only set under certain circumstances; such as when resolving instant apps
70      * or components defined in un-installed splits.
71      * @hide
72      */
73     public AuxiliaryResolveInfo auxiliaryInfo;
74 
75     /**
76      * Whether or not an instant app is available for the resolved intent.
77      */
78     public boolean isInstantAppAvailable;
79 
80     /**
81      * The IntentFilter that was matched for this ResolveInfo.
82      */
83     public IntentFilter filter;
84 
85     /**
86      * The declared priority of this match.  Comes from the "priority"
87      * attribute or, if not set, defaults to 0.  Higher values are a higher
88      * priority.
89      */
90     public int priority;
91 
92     /**
93      * Order of result according to the user's preference.  If the user
94      * has not set a preference for this result, the value is 0; higher
95      * values are a higher priority.
96      */
97     public int preferredOrder;
98 
99     /**
100      * The system's evaluation of how well the activity matches the
101      * IntentFilter.  This is a match constant, a combination of
102      * {@link IntentFilter#MATCH_CATEGORY_MASK IntentFilter.MATCH_CATEGORY_MASK}
103      * and {@link IntentFilter#MATCH_ADJUSTMENT_MASK IntentFiler.MATCH_ADJUSTMENT_MASK}.
104      */
105     public int match;
106 
107     /**
108      * Only set when returned by
109      * {@link PackageManager#queryIntentActivityOptions}, this tells you
110      * which of the given specific intents this result came from.  0 is the
111      * first in the list, < 0 means it came from the generic Intent query.
112      */
113     public int specificIndex = -1;
114 
115     /**
116      * This filter has specified the Intent.CATEGORY_DEFAULT, meaning it
117      * would like to be considered a default action that the user can
118      * perform on this data.
119      */
120     public boolean isDefault;
121 
122     /**
123      * A string resource identifier (in the package's resources) of this
124      * match's label.  From the "label" attribute or, if not set, 0.
125      */
126     public int labelRes;
127 
128     /**
129      * The actual string retrieve from <var>labelRes</var> or null if none
130      * was provided.
131      */
132     public CharSequence nonLocalizedLabel;
133 
134     /**
135      * A drawable resource identifier (in the package's resources) of this
136      * match's icon.  From the "icon" attribute or, if not set, 0. It is
137      * set only if the icon can be obtained by resource id alone.
138      */
139     public int icon;
140 
141     /**
142      * Optional -- if non-null, the {@link #labelRes} and {@link #icon}
143      * resources will be loaded from this package, rather than the one
144      * containing the resolved component.
145      */
146     public String resolvePackageName;
147 
148     /**
149      * If not equal to UserHandle.USER_CURRENT, then the intent will be forwarded to this user.
150      * @hide
151      */
152     @UnsupportedAppUsage
153     public int targetUserId;
154 
155     /**
156      * Set to true if the icon cannot be obtained by resource ids alone.
157      * It is set to true for ResolveInfos from the managed profile: They need to
158      * have their icon badged, so it cannot be obtained by resource ids alone.
159      * @hide
160      */
161     public boolean noResourceId;
162 
163     /**
164      * Same as {@link #icon} but it will always correspond to "icon" attribute
165      * regardless of {@link #noResourceId} value.
166      * @hide
167      */
168     public int iconResourceId;
169 
170     /**
171      * @hide Target comes from system process?
172      */
173     @UnsupportedAppUsage
174     public boolean system;
175 
176     /**
177      * Will be set to {@code true} if the {@link IntentFilter} responsible for intent
178      * resolution is classified as a "browser".
179      *
180      * @hide
181      */
182     @SystemApi
183     public boolean handleAllWebDataURI;
184 
185     /** {@hide} */
186     @UnsupportedAppUsage
getComponentInfo()187     public ComponentInfo getComponentInfo() {
188         if (activityInfo != null) return activityInfo;
189         if (serviceInfo != null) return serviceInfo;
190         if (providerInfo != null) return providerInfo;
191         throw new IllegalStateException("Missing ComponentInfo!");
192     }
193 
194     /**
195      * Retrieve the current textual label associated with this resolution.  This
196      * will call back on the given PackageManager to load the label from
197      * the application.
198      *
199      * @param pm A PackageManager from which the label can be loaded; usually
200      * the PackageManager from which you originally retrieved this item.
201      *
202      * @return Returns a CharSequence containing the resolutions's label.  If the
203      * item does not have a label, its name is returned.
204      */
loadLabel(PackageManager pm)205     public CharSequence loadLabel(PackageManager pm) {
206         if (nonLocalizedLabel != null) {
207             return nonLocalizedLabel;
208         }
209         CharSequence label;
210         if (resolvePackageName != null && labelRes != 0) {
211             label = pm.getText(resolvePackageName, labelRes, null);
212             if (label != null) {
213                 return label.toString().trim();
214             }
215         }
216         ComponentInfo ci = getComponentInfo();
217         ApplicationInfo ai = ci.applicationInfo;
218         if (labelRes != 0) {
219             label = pm.getText(ci.packageName, labelRes, ai);
220             if (label != null) {
221                 return label.toString().trim();
222             }
223         }
224 
225         CharSequence data = ci.loadLabel(pm);
226         // Make the data safe
227         if (data != null) data = data.toString().trim();
228         return data;
229     }
230 
231     /**
232      * @return The resource that would be used when loading
233      * the label for this resolve info.
234      *
235      * @hide
236      */
resolveLabelResId()237     public int resolveLabelResId() {
238         if (labelRes != 0) {
239             return labelRes;
240         }
241         final ComponentInfo componentInfo = getComponentInfo();
242         if (componentInfo.labelRes != 0) {
243             return componentInfo.labelRes;
244         }
245         return componentInfo.applicationInfo.labelRes;
246     }
247 
248     /**
249      * @return The resource that would be used when loading
250      * the icon for this resolve info.
251      *
252      * @hide
253      */
resolveIconResId()254     public int resolveIconResId() {
255         if (icon != 0) {
256             return icon;
257         }
258         final ComponentInfo componentInfo = getComponentInfo();
259         if (componentInfo.icon != 0) {
260             return componentInfo.icon;
261         }
262         return componentInfo.applicationInfo.icon;
263     }
264 
265     /**
266      * Retrieve the current graphical icon associated with this resolution.  This
267      * will call back on the given PackageManager to load the icon from
268      * the application.
269      *
270      * @param pm A PackageManager from which the icon can be loaded; usually
271      * the PackageManager from which you originally retrieved this item.
272      *
273      * @return Returns a Drawable containing the resolution's icon.  If the
274      * item does not have an icon, the default activity icon is returned.
275      */
loadIcon(PackageManager pm)276     public Drawable loadIcon(PackageManager pm) {
277         Drawable dr = null;
278         if (resolvePackageName != null && iconResourceId != 0) {
279             dr = pm.getDrawable(resolvePackageName, iconResourceId, null);
280         }
281         ComponentInfo ci = getComponentInfo();
282         if (dr == null && iconResourceId != 0) {
283             ApplicationInfo ai = ci.applicationInfo;
284             dr = pm.getDrawable(ci.packageName, iconResourceId, ai);
285         }
286         if (dr != null) {
287             return pm.getUserBadgedIcon(dr, new UserHandle(pm.getUserId()));
288         }
289         return ci.loadIcon(pm);
290     }
291 
292     /**
293      * Return the icon resource identifier to use for this match.  If the
294      * match defines an icon, that is used; else if the activity defines
295      * an icon, that is used; else, the application icon is used.
296      * This function does not check noResourceId flag.
297      *
298      * @return The icon associated with this match.
299      */
getIconResourceInternal()300     final int getIconResourceInternal() {
301         if (iconResourceId != 0) return iconResourceId;
302         final ComponentInfo ci = getComponentInfo();
303         if (ci != null) {
304             return ci.getIconResource();
305         }
306         return 0;
307     }
308 
309     /**
310      * Return the icon resource identifier to use for this match.  If the
311      * match defines an icon, that is used; else if the activity defines
312      * an icon, that is used; else, the application icon is used.
313      *
314      * @return The icon associated with this match.
315      */
getIconResource()316     public final int getIconResource() {
317         if (noResourceId) return 0;
318         return getIconResourceInternal();
319     }
320 
dump(Printer pw, String prefix)321     public void dump(Printer pw, String prefix) {
322         dump(pw, prefix, PackageItemInfo.DUMP_FLAG_ALL);
323     }
324 
325     /** @hide */
dump(Printer pw, String prefix, int dumpFlags)326     public void dump(Printer pw, String prefix, int dumpFlags) {
327         if (filter != null) {
328             pw.println(prefix + "Filter:");
329             filter.dump(pw, prefix + "  ");
330         }
331         pw.println(prefix + "priority=" + priority
332                 + " preferredOrder=" + preferredOrder
333                 + " match=0x" + Integer.toHexString(match)
334                 + " specificIndex=" + specificIndex
335                 + " isDefault=" + isDefault);
336         if (resolvePackageName != null) {
337             pw.println(prefix + "resolvePackageName=" + resolvePackageName);
338         }
339         if (labelRes != 0 || nonLocalizedLabel != null || icon != 0) {
340             pw.println(prefix + "labelRes=0x" + Integer.toHexString(labelRes)
341                     + " nonLocalizedLabel=" + nonLocalizedLabel
342                     + " icon=0x" + Integer.toHexString(icon));
343         }
344         if (activityInfo != null) {
345             pw.println(prefix + "ActivityInfo:");
346             activityInfo.dump(pw, prefix + "  ", dumpFlags);
347         } else if (serviceInfo != null) {
348             pw.println(prefix + "ServiceInfo:");
349             serviceInfo.dump(pw, prefix + "  ", dumpFlags);
350         } else if (providerInfo != null) {
351             pw.println(prefix + "ProviderInfo:");
352             providerInfo.dump(pw, prefix + "  ", dumpFlags);
353         }
354     }
355 
356     /**
357      * Returns whether this resolution represents the intent forwarder activity.
358      *
359      * @return whether this resolution represents the intent forwarder activity
360      */
isCrossProfileIntentForwarderActivity()361     public boolean isCrossProfileIntentForwarderActivity() {
362         return activityInfo != null
363                 && INTENT_FORWARDER_ACTIVITY.equals(activityInfo.targetActivity);
364     }
365 
ResolveInfo()366     public ResolveInfo() {
367         targetUserId = UserHandle.USER_CURRENT;
368     }
369 
ResolveInfo(ResolveInfo orig)370     public ResolveInfo(ResolveInfo orig) {
371         activityInfo = orig.activityInfo;
372         serviceInfo = orig.serviceInfo;
373         providerInfo = orig.providerInfo;
374         filter = orig.filter;
375         priority = orig.priority;
376         preferredOrder = orig.preferredOrder;
377         match = orig.match;
378         specificIndex = orig.specificIndex;
379         labelRes = orig.labelRes;
380         nonLocalizedLabel = orig.nonLocalizedLabel;
381         icon = orig.icon;
382         resolvePackageName = orig.resolvePackageName;
383         noResourceId = orig.noResourceId;
384         iconResourceId = orig.iconResourceId;
385         system = orig.system;
386         targetUserId = orig.targetUserId;
387         handleAllWebDataURI = orig.handleAllWebDataURI;
388         isInstantAppAvailable = orig.isInstantAppAvailable;
389     }
390 
toString()391     public String toString() {
392         final ComponentInfo ci = getComponentInfo();
393         StringBuilder sb = new StringBuilder(128);
394         sb.append("ResolveInfo{");
395         sb.append(Integer.toHexString(System.identityHashCode(this)));
396         sb.append(' ');
397         ComponentName.appendShortString(sb, ci.packageName, ci.name);
398         if (priority != 0) {
399             sb.append(" p=");
400             sb.append(priority);
401         }
402         if (preferredOrder != 0) {
403             sb.append(" o=");
404             sb.append(preferredOrder);
405         }
406         sb.append(" m=0x");
407         sb.append(Integer.toHexString(match));
408         if (targetUserId != UserHandle.USER_CURRENT) {
409             sb.append(" targetUserId=");
410             sb.append(targetUserId);
411         }
412         sb.append('}');
413         return sb.toString();
414     }
415 
describeContents()416     public int describeContents() {
417         return 0;
418     }
419 
writeToParcel(Parcel dest, int parcelableFlags)420     public void writeToParcel(Parcel dest, int parcelableFlags) {
421         if (activityInfo != null) {
422             dest.writeInt(1);
423             activityInfo.writeToParcel(dest, parcelableFlags);
424         } else if (serviceInfo != null) {
425             dest.writeInt(2);
426             serviceInfo.writeToParcel(dest, parcelableFlags);
427         } else if (providerInfo != null) {
428             dest.writeInt(3);
429             providerInfo.writeToParcel(dest, parcelableFlags);
430         } else {
431             dest.writeInt(0);
432         }
433         if (filter != null) {
434             dest.writeInt(1);
435             filter.writeToParcel(dest, parcelableFlags);
436         } else {
437             dest.writeInt(0);
438         }
439         dest.writeInt(priority);
440         dest.writeInt(preferredOrder);
441         dest.writeInt(match);
442         dest.writeInt(specificIndex);
443         dest.writeInt(labelRes);
444         TextUtils.writeToParcel(nonLocalizedLabel, dest, parcelableFlags);
445         dest.writeInt(icon);
446         dest.writeString8(resolvePackageName);
447         dest.writeInt(targetUserId);
448         dest.writeInt(system ? 1 : 0);
449         dest.writeInt(noResourceId ? 1 : 0);
450         dest.writeInt(iconResourceId);
451         dest.writeInt(handleAllWebDataURI ? 1 : 0);
452         dest.writeInt(isInstantAppAvailable ? 1 : 0);
453     }
454 
455     public static final @android.annotation.NonNull Creator<ResolveInfo> CREATOR
456             = new Creator<ResolveInfo>() {
457         public ResolveInfo createFromParcel(Parcel source) {
458             return new ResolveInfo(source);
459         }
460         public ResolveInfo[] newArray(int size) {
461             return new ResolveInfo[size];
462         }
463     };
464 
ResolveInfo(Parcel source)465     private ResolveInfo(Parcel source) {
466         activityInfo = null;
467         serviceInfo = null;
468         providerInfo = null;
469         switch (source.readInt()) {
470             case 1:
471                 activityInfo = ActivityInfo.CREATOR.createFromParcel(source);
472                 break;
473             case 2:
474                 serviceInfo = ServiceInfo.CREATOR.createFromParcel(source);
475                 break;
476             case 3:
477                 providerInfo = ProviderInfo.CREATOR.createFromParcel(source);
478                 break;
479             default:
480                 Slog.w(TAG, "Missing ComponentInfo!");
481                 break;
482         }
483         if (source.readInt() != 0) {
484             filter = IntentFilter.CREATOR.createFromParcel(source);
485         }
486         priority = source.readInt();
487         preferredOrder = source.readInt();
488         match = source.readInt();
489         specificIndex = source.readInt();
490         labelRes = source.readInt();
491         nonLocalizedLabel
492                 = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
493         icon = source.readInt();
494         resolvePackageName = source.readString8();
495         targetUserId = source.readInt();
496         system = source.readInt() != 0;
497         noResourceId = source.readInt() != 0;
498         iconResourceId = source.readInt();
499         handleAllWebDataURI = source.readInt() != 0;
500         isInstantAppAvailable = source.readInt() != 0;
501     }
502 
503     public static class DisplayNameComparator
504             implements Comparator<ResolveInfo> {
DisplayNameComparator(PackageManager pm)505         public DisplayNameComparator(PackageManager pm) {
506             mPM = pm;
507             mCollator.setStrength(Collator.PRIMARY);
508         }
509 
compare(ResolveInfo a, ResolveInfo b)510         public final int compare(ResolveInfo a, ResolveInfo b) {
511             // We want to put the one targeted to another user at the end of the dialog.
512             if (a.targetUserId != UserHandle.USER_CURRENT) {
513                 return 1;
514             }
515             if (b.targetUserId != UserHandle.USER_CURRENT) {
516                 return -1;
517             }
518             CharSequence  sa = a.loadLabel(mPM);
519             if (sa == null) sa = a.activityInfo.name;
520             CharSequence  sb = b.loadLabel(mPM);
521             if (sb == null) sb = b.activityInfo.name;
522 
523             return mCollator.compare(sa.toString(), sb.toString());
524         }
525 
526         private final Collator   mCollator = Collator.getInstance();
527         private PackageManager   mPM;
528     }
529 }
530