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