Home | History | Annotate | Download | only in pm
      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      * An auxiliary response that may modify the resolved information. This is
     65      * only set under certain circumstances; such as when resolving instant apps
     66      * or components defined in un-installed splits.
     67      * @hide
     68      */
     69     public AuxiliaryResolveInfo auxiliaryInfo;
     70 
     71     /**
     72      * Whether or not an instant app is available for the resolved intent.
     73      */
     74     public boolean isInstantAppAvailable;
     75 
     76     /** @removed */
     77     @Deprecated
     78     public boolean instantAppAvailable;
     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     public int targetUserId;
    153 
    154     /**
    155      * Set to true if the icon cannot be obtained by resource ids alone.
    156      * It is set to true for ResolveInfos from the managed profile: They need to
    157      * have their icon badged, so it cannot be obtained by resource ids alone.
    158      * @hide
    159      */
    160     public boolean noResourceId;
    161 
    162     /**
    163      * Same as {@link #icon} but it will always correspond to "icon" attribute
    164      * regardless of {@link #noResourceId} value.
    165      * @hide
    166      */
    167     public int iconResourceId;
    168 
    169     /**
    170      * @hide Target comes from system process?
    171      */
    172     public boolean system;
    173 
    174     /**
    175      * @hide Does the associated IntentFilter comes from a Browser ?
    176      */
    177     public boolean handleAllWebDataURI;
    178 
    179     /** {@hide} */
    180     public ComponentInfo getComponentInfo() {
    181         if (activityInfo != null) return activityInfo;
    182         if (serviceInfo != null) return serviceInfo;
    183         if (providerInfo != null) return providerInfo;
    184         throw new IllegalStateException("Missing ComponentInfo!");
    185     }
    186 
    187     /**
    188      * Retrieve the current textual label associated with this resolution.  This
    189      * will call back on the given PackageManager to load the label from
    190      * the application.
    191      *
    192      * @param pm A PackageManager from which the label can be loaded; usually
    193      * the PackageManager from which you originally retrieved this item.
    194      *
    195      * @return Returns a CharSequence containing the resolutions's label.  If the
    196      * item does not have a label, its name is returned.
    197      */
    198     public CharSequence loadLabel(PackageManager pm) {
    199         if (nonLocalizedLabel != null) {
    200             return nonLocalizedLabel;
    201         }
    202         CharSequence label;
    203         if (resolvePackageName != null && labelRes != 0) {
    204             label = pm.getText(resolvePackageName, labelRes, null);
    205             if (label != null) {
    206                 return label.toString().trim();
    207             }
    208         }
    209         ComponentInfo ci = getComponentInfo();
    210         ApplicationInfo ai = ci.applicationInfo;
    211         if (labelRes != 0) {
    212             label = pm.getText(ci.packageName, labelRes, ai);
    213             if (label != null) {
    214                 return label.toString().trim();
    215             }
    216         }
    217 
    218         CharSequence data = ci.loadLabel(pm);
    219         // Make the data safe
    220         if (data != null) data = data.toString().trim();
    221         return data;
    222     }
    223 
    224     /**
    225      * @return The resource that would be used when loading
    226      * the label for this resolve info.
    227      *
    228      * @hide
    229      */
    230     public int resolveLabelResId() {
    231         if (labelRes != 0) {
    232             return labelRes;
    233         }
    234         final ComponentInfo componentInfo = getComponentInfo();
    235         if (componentInfo.labelRes != 0) {
    236             return componentInfo.labelRes;
    237         }
    238         return componentInfo.applicationInfo.labelRes;
    239     }
    240 
    241     /**
    242      * @return The resource that would be used when loading
    243      * the icon for this resolve info.
    244      *
    245      * @hide
    246      */
    247     public int resolveIconResId() {
    248         if (icon != 0) {
    249             return icon;
    250         }
    251         final ComponentInfo componentInfo = getComponentInfo();
    252         if (componentInfo.icon != 0) {
    253             return componentInfo.icon;
    254         }
    255         return componentInfo.applicationInfo.icon;
    256     }
    257 
    258     /**
    259      * Retrieve the current graphical icon associated with this resolution.  This
    260      * will call back on the given PackageManager to load the icon from
    261      * the application.
    262      *
    263      * @param pm A PackageManager from which the icon can be loaded; usually
    264      * the PackageManager from which you originally retrieved this item.
    265      *
    266      * @return Returns a Drawable containing the resolution's icon.  If the
    267      * item does not have an icon, the default activity icon is returned.
    268      */
    269     public Drawable loadIcon(PackageManager pm) {
    270         Drawable dr = null;
    271         if (resolvePackageName != null && iconResourceId != 0) {
    272             dr = pm.getDrawable(resolvePackageName, iconResourceId, null);
    273         }
    274         ComponentInfo ci = getComponentInfo();
    275         if (dr == null && iconResourceId != 0) {
    276             ApplicationInfo ai = ci.applicationInfo;
    277             dr = pm.getDrawable(ci.packageName, iconResourceId, ai);
    278         }
    279         if (dr != null) {
    280             return pm.getUserBadgedIcon(dr, new UserHandle(pm.getUserId()));
    281         }
    282         return ci.loadIcon(pm);
    283     }
    284 
    285     /**
    286      * Return the icon resource identifier to use for this match.  If the
    287      * match defines an icon, that is used; else if the activity defines
    288      * an icon, that is used; else, the application icon is used.
    289      * This function does not check noResourceId flag.
    290      *
    291      * @return The icon associated with this match.
    292      */
    293     final int getIconResourceInternal() {
    294         if (iconResourceId != 0) return iconResourceId;
    295         final ComponentInfo ci = getComponentInfo();
    296         if (ci != null) {
    297             return ci.getIconResource();
    298         }
    299         return 0;
    300     }
    301 
    302     /**
    303      * Return the icon resource identifier to use for this match.  If the
    304      * match defines an icon, that is used; else if the activity defines
    305      * an icon, that is used; else, the application icon is used.
    306      *
    307      * @return The icon associated with this match.
    308      */
    309     public final int getIconResource() {
    310         if (noResourceId) return 0;
    311         return getIconResourceInternal();
    312     }
    313 
    314     public void dump(Printer pw, String prefix) {
    315         dump(pw, prefix, PackageItemInfo.DUMP_FLAG_ALL);
    316     }
    317 
    318     /** @hide */
    319     public void dump(Printer pw, String prefix, int dumpFlags) {
    320         if (filter != null) {
    321             pw.println(prefix + "Filter:");
    322             filter.dump(pw, prefix + "  ");
    323         }
    324         pw.println(prefix + "priority=" + priority
    325                 + " preferredOrder=" + preferredOrder
    326                 + " match=0x" + Integer.toHexString(match)
    327                 + " specificIndex=" + specificIndex
    328                 + " isDefault=" + isDefault);
    329         if (resolvePackageName != null) {
    330             pw.println(prefix + "resolvePackageName=" + resolvePackageName);
    331         }
    332         if (labelRes != 0 || nonLocalizedLabel != null || icon != 0) {
    333             pw.println(prefix + "labelRes=0x" + Integer.toHexString(labelRes)
    334                     + " nonLocalizedLabel=" + nonLocalizedLabel
    335                     + " icon=0x" + Integer.toHexString(icon));
    336         }
    337         if (activityInfo != null) {
    338             pw.println(prefix + "ActivityInfo:");
    339             activityInfo.dump(pw, prefix + "  ", dumpFlags);
    340         } else if (serviceInfo != null) {
    341             pw.println(prefix + "ServiceInfo:");
    342             serviceInfo.dump(pw, prefix + "  ", dumpFlags);
    343         } else if (providerInfo != null) {
    344             pw.println(prefix + "ProviderInfo:");
    345             providerInfo.dump(pw, prefix + "  ", dumpFlags);
    346         }
    347     }
    348 
    349     public ResolveInfo() {
    350         targetUserId = UserHandle.USER_CURRENT;
    351     }
    352 
    353     public ResolveInfo(ResolveInfo orig) {
    354         activityInfo = orig.activityInfo;
    355         serviceInfo = orig.serviceInfo;
    356         providerInfo = orig.providerInfo;
    357         filter = orig.filter;
    358         priority = orig.priority;
    359         preferredOrder = orig.preferredOrder;
    360         match = orig.match;
    361         specificIndex = orig.specificIndex;
    362         labelRes = orig.labelRes;
    363         nonLocalizedLabel = orig.nonLocalizedLabel;
    364         icon = orig.icon;
    365         resolvePackageName = orig.resolvePackageName;
    366         noResourceId = orig.noResourceId;
    367         iconResourceId = orig.iconResourceId;
    368         system = orig.system;
    369         targetUserId = orig.targetUserId;
    370         handleAllWebDataURI = orig.handleAllWebDataURI;
    371         isInstantAppAvailable = orig.isInstantAppAvailable;
    372         instantAppAvailable = isInstantAppAvailable;
    373     }
    374 
    375     public String toString() {
    376         final ComponentInfo ci = getComponentInfo();
    377         StringBuilder sb = new StringBuilder(128);
    378         sb.append("ResolveInfo{");
    379         sb.append(Integer.toHexString(System.identityHashCode(this)));
    380         sb.append(' ');
    381         ComponentName.appendShortString(sb, ci.packageName, ci.name);
    382         if (priority != 0) {
    383             sb.append(" p=");
    384             sb.append(priority);
    385         }
    386         if (preferredOrder != 0) {
    387             sb.append(" o=");
    388             sb.append(preferredOrder);
    389         }
    390         sb.append(" m=0x");
    391         sb.append(Integer.toHexString(match));
    392         if (targetUserId != UserHandle.USER_CURRENT) {
    393             sb.append(" targetUserId=");
    394             sb.append(targetUserId);
    395         }
    396         sb.append('}');
    397         return sb.toString();
    398     }
    399 
    400     public int describeContents() {
    401         return 0;
    402     }
    403 
    404     public void writeToParcel(Parcel dest, int parcelableFlags) {
    405         if (activityInfo != null) {
    406             dest.writeInt(1);
    407             activityInfo.writeToParcel(dest, parcelableFlags);
    408         } else if (serviceInfo != null) {
    409             dest.writeInt(2);
    410             serviceInfo.writeToParcel(dest, parcelableFlags);
    411         } else if (providerInfo != null) {
    412             dest.writeInt(3);
    413             providerInfo.writeToParcel(dest, parcelableFlags);
    414         } else {
    415             dest.writeInt(0);
    416         }
    417         if (filter != null) {
    418             dest.writeInt(1);
    419             filter.writeToParcel(dest, parcelableFlags);
    420         } else {
    421             dest.writeInt(0);
    422         }
    423         dest.writeInt(priority);
    424         dest.writeInt(preferredOrder);
    425         dest.writeInt(match);
    426         dest.writeInt(specificIndex);
    427         dest.writeInt(labelRes);
    428         TextUtils.writeToParcel(nonLocalizedLabel, dest, parcelableFlags);
    429         dest.writeInt(icon);
    430         dest.writeString(resolvePackageName);
    431         dest.writeInt(targetUserId);
    432         dest.writeInt(system ? 1 : 0);
    433         dest.writeInt(noResourceId ? 1 : 0);
    434         dest.writeInt(iconResourceId);
    435         dest.writeInt(handleAllWebDataURI ? 1 : 0);
    436         dest.writeInt(isInstantAppAvailable ? 1 : 0);
    437     }
    438 
    439     public static final Creator<ResolveInfo> CREATOR
    440             = new Creator<ResolveInfo>() {
    441         public ResolveInfo createFromParcel(Parcel source) {
    442             return new ResolveInfo(source);
    443         }
    444         public ResolveInfo[] newArray(int size) {
    445             return new ResolveInfo[size];
    446         }
    447     };
    448 
    449     private ResolveInfo(Parcel source) {
    450         activityInfo = null;
    451         serviceInfo = null;
    452         providerInfo = null;
    453         switch (source.readInt()) {
    454             case 1:
    455                 activityInfo = ActivityInfo.CREATOR.createFromParcel(source);
    456                 break;
    457             case 2:
    458                 serviceInfo = ServiceInfo.CREATOR.createFromParcel(source);
    459                 break;
    460             case 3:
    461                 providerInfo = ProviderInfo.CREATOR.createFromParcel(source);
    462                 break;
    463             default:
    464                 Slog.w(TAG, "Missing ComponentInfo!");
    465                 break;
    466         }
    467         if (source.readInt() != 0) {
    468             filter = IntentFilter.CREATOR.createFromParcel(source);
    469         }
    470         priority = source.readInt();
    471         preferredOrder = source.readInt();
    472         match = source.readInt();
    473         specificIndex = source.readInt();
    474         labelRes = source.readInt();
    475         nonLocalizedLabel
    476                 = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
    477         icon = source.readInt();
    478         resolvePackageName = source.readString();
    479         targetUserId = source.readInt();
    480         system = source.readInt() != 0;
    481         noResourceId = source.readInt() != 0;
    482         iconResourceId = source.readInt();
    483         handleAllWebDataURI = source.readInt() != 0;
    484         instantAppAvailable = isInstantAppAvailable = source.readInt() != 0;
    485     }
    486 
    487     public static class DisplayNameComparator
    488             implements Comparator<ResolveInfo> {
    489         public DisplayNameComparator(PackageManager pm) {
    490             mPM = pm;
    491             mCollator.setStrength(Collator.PRIMARY);
    492         }
    493 
    494         public final int compare(ResolveInfo a, ResolveInfo b) {
    495             // We want to put the one targeted to another user at the end of the dialog.
    496             if (a.targetUserId != UserHandle.USER_CURRENT) {
    497                 return 1;
    498             }
    499             if (b.targetUserId != UserHandle.USER_CURRENT) {
    500                 return -1;
    501             }
    502             CharSequence  sa = a.loadLabel(mPM);
    503             if (sa == null) sa = a.activityInfo.name;
    504             CharSequence  sb = b.loadLabel(mPM);
    505             if (sb == null) sb = b.activityInfo.name;
    506 
    507             return mCollator.compare(sa.toString(), sb.toString());
    508         }
    509 
    510         private final Collator   mCollator = Collator.getInstance();
    511         private PackageManager   mPM;
    512     }
    513 }
    514