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