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 PackageItemInfo()101 public PackageItemInfo() { 102 showUserIcon = UserHandle.USER_NULL; 103 } 104 PackageItemInfo(PackageItemInfo orig)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 */ loadLabel(PackageManager pm)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 loadSafeLabel(@onNull PackageManager pm)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 */ loadIcon(PackageManager pm)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 */ loadUnbadgedIcon(PackageManager pm)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 */ loadBanner(PackageManager pm)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 */ loadDefaultIcon(PackageManager pm)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 */ loadDefaultBanner(PackageManager pm)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 */ loadLogo(PackageManager pm)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 */ loadDefaultLogo(PackageManager pm)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 */ loadXmlMetaData(PackageManager pm, String name)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 dumpFront(Printer pw, String prefix)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 dumpBack(Printer pw, String prefix)373 protected void dumpBack(Printer pw, String prefix) { 374 // no back here 375 } 376 writeToParcel(Parcel dest, int parcelableFlags)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 PackageItemInfo(Parcel source)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 */ getApplicationInfo()410 protected ApplicationInfo getApplicationInfo() { 411 return null; 412 } 413 414 public static class DisplayNameComparator 415 implements Comparator<PackageItemInfo> { DisplayNameComparator(PackageManager pm)416 public DisplayNameComparator(PackageManager pm) { 417 mPM = pm; 418 } 419 compare(PackageItemInfo aa, PackageItemInfo ab)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