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