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