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.annotation.NonNull;
     20 import android.annotation.SystemApi;
     21 import android.content.res.XmlResourceParser;
     22 
     23 import android.graphics.drawable.Drawable;
     24 import android.os.Bundle;
     25 import android.os.Parcel;
     26 import android.os.UserHandle;
     27 import android.text.Html;
     28 import android.text.TextPaint;
     29 import android.text.TextUtils;
     30 import android.util.Printer;
     31 import java.text.Collator;
     32 import java.util.Comparator;
     33 
     34 /**
     35  * Base class containing information common to all package items held by
     36  * the package manager.  This provides a very common basic set of attributes:
     37  * a label, icon, and meta-data.  This class is not intended
     38  * to be used by itself; it is simply here to share common definitions
     39  * between all items returned by the package manager.  As such, it does not
     40  * itself implement Parcelable, but does provide convenience methods to assist
     41  * in the implementation of Parcelable in subclasses.
     42  */
     43 public class PackageItemInfo {
     44     private static final float MAX_LABEL_SIZE_PX = 500f;
     45     /**
     46      * Public name of this item. From the "android:name" attribute.
     47      */
     48     public String name;
     49 
     50     /**
     51      * Name of the package that this item is in.
     52      */
     53     public String packageName;
     54 
     55     /**
     56      * A string resource identifier (in the package's resources) of this
     57      * component's label.  From the "label" attribute or, if not set, 0.
     58      */
     59     public int labelRes;
     60 
     61     /**
     62      * The string provided in the AndroidManifest file, if any.  You
     63      * probably don't want to use this.  You probably want
     64      * {@link PackageManager#getApplicationLabel}
     65      */
     66     public CharSequence nonLocalizedLabel;
     67 
     68     /**
     69      * A drawable resource identifier (in the package's resources) of this
     70      * component's icon.  From the "icon" attribute or, if not set, 0.
     71      */
     72     public int icon;
     73 
     74     /**
     75      * A drawable resource identifier (in the package's resources) of this
     76      * component's banner.  From the "banner" attribute or, if not set, 0.
     77      */
     78     public int banner;
     79 
     80     /**
     81      * A drawable resource identifier (in the package's resources) of this
     82      * component's logo. Logos may be larger/wider than icons and are
     83      * displayed by certain UI elements in place of a name or name/icon
     84      * combination. From the "logo" attribute or, if not set, 0.
     85      */
     86     public int logo;
     87 
     88     /**
     89      * Additional meta-data associated with this component.  This field
     90      * will only be filled in if you set the
     91      * {@link PackageManager#GET_META_DATA} flag when requesting the info.
     92      */
     93     public Bundle metaData;
     94 
     95     /**
     96      * If different of UserHandle.USER_NULL, The icon of this item will be the one of that user.
     97      * @hide
     98      */
     99     public int showUserIcon;
    100 
    101     public PackageItemInfo() {
    102         showUserIcon = UserHandle.USER_NULL;
    103     }
    104 
    105     public PackageItemInfo(PackageItemInfo orig) {
    106         name = orig.name;
    107         if (name != null) name = name.trim();
    108         packageName = orig.packageName;
    109         labelRes = orig.labelRes;
    110         nonLocalizedLabel = orig.nonLocalizedLabel;
    111         if (nonLocalizedLabel != null) nonLocalizedLabel = nonLocalizedLabel.toString().trim();
    112         icon = orig.icon;
    113         banner = orig.banner;
    114         logo = orig.logo;
    115         metaData = orig.metaData;
    116         showUserIcon = orig.showUserIcon;
    117     }
    118 
    119     /**
    120      * Retrieve the current textual label associated with this item.  This
    121      * will call back on the given PackageManager to load the label from
    122      * the application.
    123      *
    124      * @param pm A PackageManager from which the label can be loaded; usually
    125      * the PackageManager from which you originally retrieved this item.
    126      *
    127      * @return Returns a CharSequence containing the item's label.  If the
    128      * item does not have a label, its name is returned.
    129      */
    130     public CharSequence loadLabel(PackageManager pm) {
    131         if (nonLocalizedLabel != null) {
    132             return nonLocalizedLabel;
    133         }
    134         if (labelRes != 0) {
    135             CharSequence label = pm.getText(packageName, labelRes, getApplicationInfo());
    136             if (label != null) {
    137                 return label.toString().trim();
    138             }
    139         }
    140         if (name != null) {
    141             return name;
    142         }
    143         return packageName;
    144     }
    145 
    146     /**
    147      * Same as {@link #loadLabel(PackageManager)} with the addition that
    148      * the returned label is safe for being presented in the UI since it
    149      * will not contain new lines and the length will be limited to a
    150      * reasonable amount. This prevents a malicious party to influence UI
    151      * layout via the app label misleading the user into performing a
    152      * detrimental for them action. If the label is too long it will be
    153      * truncated and ellipsized at the end.
    154      *
    155      * @param pm A PackageManager from which the label can be loaded; usually
    156      * the PackageManager from which you originally retrieved this item
    157      * @return Returns a CharSequence containing the item's label. If the
    158      * item does not have a label, its name is returned.
    159      *
    160      * @hide
    161      */
    162     @SystemApi
    163     public @NonNull CharSequence loadSafeLabel(@NonNull PackageManager pm) {
    164         // loadLabel() always returns non-null
    165         String label = loadLabel(pm).toString();
    166         // strip HTML tags to avoid <br> and other tags overwriting original message
    167         String labelStr = Html.fromHtml(label).toString();
    168 
    169         // If the label contains new line characters it may push the UI
    170         // down to hide a part of it. Labels shouldn't have new line
    171         // characters, so just truncate at the first time one is seen.
    172         final int labelLength = labelStr.length();
    173         int offset = 0;
    174         while (offset < labelLength) {
    175             final int codePoint = labelStr.codePointAt(offset);
    176             final int type = Character.getType(codePoint);
    177             if (type == Character.LINE_SEPARATOR
    178                     || type == Character.CONTROL
    179                     || type == Character.PARAGRAPH_SEPARATOR) {
    180                 labelStr = labelStr.substring(0, offset);
    181                 break;
    182             }
    183             // replace all non-break space to " " in order to be trimmed
    184             if (type == Character.SPACE_SEPARATOR) {
    185                 labelStr = labelStr.substring(0, offset) + " " + labelStr.substring(offset +
    186                         Character.charCount(codePoint));
    187             }
    188             offset += Character.charCount(codePoint);
    189         }
    190 
    191         labelStr = labelStr.trim();
    192         if (labelStr.isEmpty()) {
    193             return packageName;
    194         }
    195         TextPaint paint = new TextPaint();
    196         paint.setTextSize(42);
    197 
    198         return TextUtils.ellipsize(labelStr, paint, MAX_LABEL_SIZE_PX,
    199                 TextUtils.TruncateAt.END);
    200     }
    201 
    202     /**
    203      * Retrieve the current graphical icon associated with this item.  This
    204      * will call back on the given PackageManager to load the icon from
    205      * the application.
    206      *
    207      * @param pm A PackageManager from which the icon can be loaded; usually
    208      * the PackageManager from which you originally retrieved this item.
    209      *
    210      * @return Returns a Drawable containing the item's icon.  If the
    211      * item does not have an icon, the item's default icon is returned
    212      * such as the default activity icon.
    213      */
    214     public Drawable loadIcon(PackageManager pm) {
    215         return pm.loadItemIcon(this, getApplicationInfo());
    216     }
    217 
    218     /**
    219      * Retrieve the current graphical icon associated with this item without
    220      * the addition of a work badge if applicable.
    221      * This will call back on the given PackageManager to load the icon from
    222      * the application.
    223      *
    224      * @param pm A PackageManager from which the icon can be loaded; usually
    225      * the PackageManager from which you originally retrieved this item.
    226      *
    227      * @return Returns a Drawable containing the item's icon.  If the
    228      * item does not have an icon, the item's default icon is returned
    229      * such as the default activity icon.
    230      */
    231     public Drawable loadUnbadgedIcon(PackageManager pm) {
    232         return pm.loadUnbadgedItemIcon(this, getApplicationInfo());
    233     }
    234 
    235     /**
    236      * Retrieve the current graphical banner associated with this item.  This
    237      * will call back on the given PackageManager to load the banner from
    238      * the application.
    239      *
    240      * @param pm A PackageManager from which the banner can be loaded; usually
    241      * the PackageManager from which you originally retrieved this item.
    242      *
    243      * @return Returns a Drawable containing the item's banner.  If the item
    244      * does not have a banner, this method will return null.
    245      */
    246     public Drawable loadBanner(PackageManager pm) {
    247         if (banner != 0) {
    248             Drawable dr = pm.getDrawable(packageName, banner, getApplicationInfo());
    249             if (dr != null) {
    250                 return dr;
    251             }
    252         }
    253         return loadDefaultBanner(pm);
    254     }
    255 
    256     /**
    257      * Retrieve the default graphical icon associated with this item.
    258      *
    259      * @param pm A PackageManager from which the icon can be loaded; usually
    260      * the PackageManager from which you originally retrieved this item.
    261      *
    262      * @return Returns a Drawable containing the item's default icon
    263      * such as the default activity icon.
    264      *
    265      * @hide
    266      */
    267     public Drawable loadDefaultIcon(PackageManager pm) {
    268         return pm.getDefaultActivityIcon();
    269     }
    270 
    271     /**
    272      * Retrieve the default graphical banner associated with this item.
    273      *
    274      * @param pm A PackageManager from which the banner can be loaded; usually
    275      * the PackageManager from which you originally retrieved this item.
    276      *
    277      * @return Returns a Drawable containing the item's default banner
    278      * or null if no default logo is available.
    279      *
    280      * @hide
    281      */
    282     protected Drawable loadDefaultBanner(PackageManager pm) {
    283         return null;
    284     }
    285 
    286     /**
    287      * Retrieve the current graphical logo associated with this item. This
    288      * will call back on the given PackageManager to load the logo from
    289      * the application.
    290      *
    291      * @param pm A PackageManager from which the logo can be loaded; usually
    292      * the PackageManager from which you originally retrieved this item.
    293      *
    294      * @return Returns a Drawable containing the item's logo. If the item
    295      * does not have a logo, this method will return null.
    296      */
    297     public Drawable loadLogo(PackageManager pm) {
    298         if (logo != 0) {
    299             Drawable d = pm.getDrawable(packageName, logo, getApplicationInfo());
    300             if (d != null) {
    301                 return d;
    302             }
    303         }
    304         return loadDefaultLogo(pm);
    305     }
    306 
    307     /**
    308      * Retrieve the default graphical logo associated with this item.
    309      *
    310      * @param pm A PackageManager from which the logo can be loaded; usually
    311      * the PackageManager from which you originally retrieved this item.
    312      *
    313      * @return Returns a Drawable containing the item's default logo
    314      * or null if no default logo is available.
    315      *
    316      * @hide
    317      */
    318     protected Drawable loadDefaultLogo(PackageManager pm) {
    319         return null;
    320     }
    321 
    322     /**
    323      * Load an XML resource attached to the meta-data of this item.  This will
    324      * retrieved the name meta-data entry, and if defined call back on the
    325      * given PackageManager to load its XML file from the application.
    326      *
    327      * @param pm A PackageManager from which the XML can be loaded; usually
    328      * the PackageManager from which you originally retrieved this item.
    329      * @param name Name of the meta-date you would like to load.
    330      *
    331      * @return Returns an XmlPullParser you can use to parse the XML file
    332      * assigned as the given meta-data.  If the meta-data name is not defined
    333      * or the XML resource could not be found, null is returned.
    334      */
    335     public XmlResourceParser loadXmlMetaData(PackageManager pm, String name) {
    336         if (metaData != null) {
    337             int resid = metaData.getInt(name);
    338             if (resid != 0) {
    339                 return pm.getXml(packageName, resid, getApplicationInfo());
    340             }
    341         }
    342         return null;
    343     }
    344 
    345     /**
    346      * @hide Flag for dumping: include all details.
    347      */
    348     public static final int DUMP_FLAG_DETAILS = 1<<0;
    349 
    350     /**
    351      * @hide Flag for dumping: include nested ApplicationInfo.
    352      */
    353     public static final int DUMP_FLAG_APPLICATION = 1<<1;
    354 
    355     /**
    356      * @hide Flag for dumping: all flags to dump everything.
    357      */
    358     public static final int DUMP_FLAG_ALL = DUMP_FLAG_DETAILS | DUMP_FLAG_APPLICATION;
    359 
    360     protected void dumpFront(Printer pw, String prefix) {
    361         if (name != null) {
    362             pw.println(prefix + "name=" + name);
    363         }
    364         pw.println(prefix + "packageName=" + packageName);
    365         if (labelRes != 0 || nonLocalizedLabel != null || icon != 0 || banner != 0) {
    366             pw.println(prefix + "labelRes=0x" + Integer.toHexString(labelRes)
    367                     + " nonLocalizedLabel=" + nonLocalizedLabel
    368                     + " icon=0x" + Integer.toHexString(icon)
    369                     + " banner=0x" + Integer.toHexString(banner));
    370         }
    371     }
    372 
    373     protected void dumpBack(Printer pw, String prefix) {
    374         // no back here
    375     }
    376 
    377     public void writeToParcel(Parcel dest, int parcelableFlags) {
    378         dest.writeString(name);
    379         dest.writeString(packageName);
    380         dest.writeInt(labelRes);
    381         TextUtils.writeToParcel(nonLocalizedLabel, dest, parcelableFlags);
    382         dest.writeInt(icon);
    383         dest.writeInt(logo);
    384         dest.writeBundle(metaData);
    385         dest.writeInt(banner);
    386         dest.writeInt(showUserIcon);
    387     }
    388 
    389     protected PackageItemInfo(Parcel source) {
    390         name = source.readString();
    391         packageName = source.readString();
    392         labelRes = source.readInt();
    393         nonLocalizedLabel
    394                 = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
    395         icon = source.readInt();
    396         logo = source.readInt();
    397         metaData = source.readBundle();
    398         banner = source.readInt();
    399         showUserIcon = source.readInt();
    400     }
    401 
    402     /**
    403      * Get the ApplicationInfo for the application to which this item belongs,
    404      * if available, otherwise returns null.
    405      *
    406      * @return Returns the ApplicationInfo of this item, or null if not known.
    407      *
    408      * @hide
    409      */
    410     protected ApplicationInfo getApplicationInfo() {
    411         return null;
    412     }
    413 
    414     public static class DisplayNameComparator
    415             implements Comparator<PackageItemInfo> {
    416         public DisplayNameComparator(PackageManager pm) {
    417             mPM = pm;
    418         }
    419 
    420         public final int compare(PackageItemInfo aa, PackageItemInfo ab) {
    421             CharSequence  sa = aa.loadLabel(mPM);
    422             if (sa == null) sa = aa.name;
    423             CharSequence  sb = ab.loadLabel(mPM);
    424             if (sb == null) sb = ab.name;
    425             return sCollator.compare(sa.toString(), sb.toString());
    426         }
    427 
    428         private final Collator   sCollator = Collator.getInstance();
    429         private PackageManager   mPM;
    430     }
    431 }
    432