PackageItemInfo.java revision be2865a60a470c6248bdd7155f79d57239baa0f1
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 17package android.content.pm; 18 19import android.annotation.NonNull; 20import android.annotation.SystemApi; 21import android.content.res.XmlResourceParser; 22 23import android.graphics.drawable.Drawable; 24import android.os.Bundle; 25import android.os.Parcel; 26import android.text.TextUtils; 27import android.util.Printer; 28import android.text.BidiFormatter; 29import android.text.TextPaint; 30import android.text.Html; 31import java.text.Collator; 32import 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 */ 43public 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 logo. Logos may be larger/wider than icons and are 77 * displayed by certain UI elements in place of a name or name/icon 78 * combination. From the "logo" attribute or, if not set, 0. 79 */ 80 public int logo; 81 82 /** 83 * Additional meta-data associated with this component. This field 84 * will only be filled in if you set the 85 * {@link PackageManager#GET_META_DATA} flag when requesting the info. 86 */ 87 public Bundle metaData; 88 89 public PackageItemInfo() { 90 } 91 92 public PackageItemInfo(PackageItemInfo orig) { 93 name = orig.name; 94 if (name != null) name = name.trim(); 95 packageName = orig.packageName; 96 labelRes = orig.labelRes; 97 nonLocalizedLabel = orig.nonLocalizedLabel; 98 if (nonLocalizedLabel != null) nonLocalizedLabel = nonLocalizedLabel.toString().trim(); 99 icon = orig.icon; 100 logo = orig.logo; 101 metaData = orig.metaData; 102 } 103 104 /** 105 * Retrieve the current textual label associated with this item. This 106 * will call back on the given PackageManager to load the label from 107 * the application. 108 * 109 * @param pm A PackageManager from which the label can be loaded; usually 110 * the PackageManager from which you originally retrieved this item. 111 * 112 * @return Returns a CharSequence containing the item's label. If the 113 * item does not have a label, its name is returned. 114 */ 115 public CharSequence loadLabel(PackageManager pm) { 116 if (nonLocalizedLabel != null) { 117 return nonLocalizedLabel; 118 } 119 if (labelRes != 0) { 120 CharSequence label = pm.getText(packageName, labelRes, getApplicationInfo()); 121 if (label != null) { 122 return label.toString().trim(); 123 } 124 } 125 if (name != null) { 126 return name; 127 } 128 return packageName; 129 } 130 131 /** 132 * Same as {@link #loadLabel(PackageManager)} with the addition that 133 * the returned label is safe for being presented in the UI since it 134 * will not contain new lines and the length will be limited to a 135 * reasonable amount. This prevents a malicious party to influence UI 136 * layout via the app label misleading the user into performing a 137 * detrimental for them action. If the label is too long it will be 138 * truncated and ellipsized at the end. 139 * 140 * @param pm A PackageManager from which the label can be loaded; usually 141 * the PackageManager from which you originally retrieved this item 142 * @return Returns a CharSequence containing the item's label. If the 143 * item does not have a label, its name is returned. 144 * 145 * @hide 146 */ 147 @SystemApi 148 public @NonNull CharSequence loadSafeLabel(@NonNull PackageManager pm) { 149 // loadLabel() always returns non-null 150 String label = loadLabel(pm).toString(); 151 // strip HTML tags to avoid <br> and other tags overwriting original message 152 String labelStr = Html.fromHtml(label).toString(); 153 154 // If the label contains new line characters it may push the UI 155 // down to hide a part of it. Labels shouldn't have new line 156 // characters, so just truncate at the first time one is seen. 157 final int labelLength = labelStr.length(); 158 int offset = 0; 159 while (offset < labelLength) { 160 final int codePoint = labelStr.codePointAt(offset); 161 final int type = Character.getType(codePoint); 162 if (type == Character.LINE_SEPARATOR 163 || type == Character.CONTROL 164 || type == Character.PARAGRAPH_SEPARATOR) { 165 labelStr = labelStr.substring(0, offset); 166 break; 167 } 168 // replace all non-break space to " " in order to be trimmed 169 if (type == Character.SPACE_SEPARATOR) { 170 labelStr = labelStr.substring(0, offset) + " " + labelStr.substring(offset + 171 Character.charCount(codePoint)); 172 } 173 offset += Character.charCount(codePoint); 174 } 175 176 labelStr = labelStr.trim(); 177 if (labelStr.isEmpty()) { 178 return packageName; 179 } 180 TextPaint paint = new TextPaint(); 181 paint.setTextSize(42); 182 183 return TextUtils.ellipsize(labelStr, paint, MAX_LABEL_SIZE_PX, 184 TextUtils.TruncateAt.END); 185 } 186 /** 187 * Retrieve the current graphical icon associated with this item. This 188 * will call back on the given PackageManager to load the icon from 189 * the application. 190 * 191 * @param pm A PackageManager from which the icon can be loaded; usually 192 * the PackageManager from which you originally retrieved this item. 193 * 194 * @return Returns a Drawable containing the item's icon. If the 195 * item does not have an icon, the item's default icon is returned 196 * such as the default activity icon. 197 */ 198 public Drawable loadIcon(PackageManager pm) { 199 if (icon != 0) { 200 Drawable dr = pm.getDrawable(packageName, icon, getApplicationInfo()); 201 if (dr != null) { 202 return dr; 203 } 204 } 205 return loadDefaultIcon(pm); 206 } 207 208 /** 209 * Retrieve the default graphical icon associated with this item. 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 item's default icon 215 * such as the default activity icon. 216 * 217 * @hide 218 */ 219 protected Drawable loadDefaultIcon(PackageManager pm) { 220 return pm.getDefaultActivityIcon(); 221 } 222 223 /** 224 * Retrieve the current graphical logo associated with this item. This 225 * will call back on the given PackageManager to load the logo from 226 * the application. 227 * 228 * @param pm A PackageManager from which the logo can be loaded; usually 229 * the PackageManager from which you originally retrieved this item. 230 * 231 * @return Returns a Drawable containing the item's logo. If the item 232 * does not have a logo, this method will return null. 233 */ 234 public Drawable loadLogo(PackageManager pm) { 235 if (logo != 0) { 236 Drawable d = pm.getDrawable(packageName, logo, getApplicationInfo()); 237 if (d != null) { 238 return d; 239 } 240 } 241 return loadDefaultLogo(pm); 242 } 243 244 /** 245 * Retrieve the default graphical logo associated with this item. 246 * 247 * @param pm A PackageManager from which the logo can be loaded; usually 248 * the PackageManager from which you originally retrieved this item. 249 * 250 * @return Returns a Drawable containing the item's default logo 251 * or null if no default logo is available. 252 * 253 * @hide 254 */ 255 protected Drawable loadDefaultLogo(PackageManager pm) { 256 return null; 257 } 258 259 /** 260 * Load an XML resource attached to the meta-data of this item. This will 261 * retrieved the name meta-data entry, and if defined call back on the 262 * given PackageManager to load its XML file from the application. 263 * 264 * @param pm A PackageManager from which the XML can be loaded; usually 265 * the PackageManager from which you originally retrieved this item. 266 * @param name Name of the meta-date you would like to load. 267 * 268 * @return Returns an XmlPullParser you can use to parse the XML file 269 * assigned as the given meta-data. If the meta-data name is not defined 270 * or the XML resource could not be found, null is returned. 271 */ 272 public XmlResourceParser loadXmlMetaData(PackageManager pm, String name) { 273 if (metaData != null) { 274 int resid = metaData.getInt(name); 275 if (resid != 0) { 276 return pm.getXml(packageName, resid, getApplicationInfo()); 277 } 278 } 279 return null; 280 } 281 282 protected void dumpFront(Printer pw, String prefix) { 283 if (name != null) { 284 pw.println(prefix + "name=" + name); 285 } 286 pw.println(prefix + "packageName=" + packageName); 287 if (labelRes != 0 || nonLocalizedLabel != null || icon != 0) { 288 pw.println(prefix + "labelRes=0x" + Integer.toHexString(labelRes) 289 + " nonLocalizedLabel=" + nonLocalizedLabel 290 + " icon=0x" + Integer.toHexString(icon)); 291 } 292 } 293 294 protected void dumpBack(Printer pw, String prefix) { 295 // no back here 296 } 297 298 public void writeToParcel(Parcel dest, int parcelableFlags) { 299 dest.writeString(name); 300 dest.writeString(packageName); 301 dest.writeInt(labelRes); 302 TextUtils.writeToParcel(nonLocalizedLabel, dest, parcelableFlags); 303 dest.writeInt(icon); 304 dest.writeInt(logo); 305 dest.writeBundle(metaData); 306 } 307 308 protected PackageItemInfo(Parcel source) { 309 name = source.readString(); 310 packageName = source.readString(); 311 labelRes = source.readInt(); 312 nonLocalizedLabel 313 = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source); 314 icon = source.readInt(); 315 logo = source.readInt(); 316 metaData = source.readBundle(); 317 } 318 319 /** 320 * Get the ApplicationInfo for the application to which this item belongs, 321 * if available, otherwise returns null. 322 * 323 * @return Returns the ApplicationInfo of this item, or null if not known. 324 * 325 * @hide 326 */ 327 protected ApplicationInfo getApplicationInfo() { 328 return null; 329 } 330 331 public static class DisplayNameComparator 332 implements Comparator<PackageItemInfo> { 333 public DisplayNameComparator(PackageManager pm) { 334 mPM = pm; 335 } 336 337 public final int compare(PackageItemInfo aa, PackageItemInfo ab) { 338 CharSequence sa = aa.loadLabel(mPM); 339 if (sa == null) sa = aa.name; 340 CharSequence sb = ab.loadLabel(mPM); 341 if (sb == null) sb = ab.name; 342 return sCollator.compare(sa.toString(), sb.toString()); 343 } 344 345 private final Collator sCollator = Collator.getInstance(); 346 private PackageManager mPM; 347 } 348} 349