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 static android.text.TextUtils.SAFE_STRING_FLAG_FIRST_LINE; 20 import static android.text.TextUtils.SAFE_STRING_FLAG_SINGLE_LINE; 21 import static android.text.TextUtils.SAFE_STRING_FLAG_TRIM; 22 import static android.text.TextUtils.makeSafeForPresentation; 23 24 import android.annotation.FloatRange; 25 import android.annotation.NonNull; 26 import android.annotation.SystemApi; 27 import android.app.ActivityThread; 28 import android.content.res.XmlResourceParser; 29 import android.graphics.drawable.Drawable; 30 import android.os.Bundle; 31 import android.os.Parcel; 32 import android.os.UserHandle; 33 import android.text.TextUtils; 34 import android.util.Printer; 35 import android.util.proto.ProtoOutputStream; 36 37 38 import java.text.Collator; 39 import java.util.Comparator; 40 import java.util.Objects; 41 42 /** 43 * Base class containing information common to all package items held by 44 * the package manager. This provides a very common basic set of attributes: 45 * a label, icon, and meta-data. This class is not intended 46 * to be used by itself; it is simply here to share common definitions 47 * between all items returned by the package manager. As such, it does not 48 * itself implement Parcelable, but does provide convenience methods to assist 49 * in the implementation of Parcelable in subclasses. 50 */ 51 public class PackageItemInfo { 52 53 /** 54 * The maximum length of a safe label, in characters 55 * 56 * TODO(b/157997155): It may make sense to expose this publicly so that apps can check for the 57 * value and truncate the strings/use a different label, without having to hardcode and make 58 * assumptions about the value. 59 * @hide 60 */ 61 public static final int MAX_SAFE_LABEL_LENGTH = 1000; 62 63 /** @hide */ 64 public static final float DEFAULT_MAX_LABEL_SIZE_PX = 500f; 65 66 /** 67 * Remove {@link Character#isWhitespace(int) whitespace} and non-breaking spaces from the edges 68 * of the label. 69 * 70 * @see #loadSafeLabel(PackageManager, float, int) 71 * 72 * @deprecated Use {@link TextUtils#SAFE_STRING_FLAG_TRIM} instead 73 * @hide 74 * @removed 75 */ 76 @Deprecated 77 @SystemApi 78 public static final int SAFE_LABEL_FLAG_TRIM = SAFE_STRING_FLAG_TRIM; 79 80 /** 81 * Force entire string into single line of text (no newlines). Cannot be set at the same time as 82 * {@link #SAFE_LABEL_FLAG_FIRST_LINE}. 83 * 84 * @see #loadSafeLabel(PackageManager, float, int) 85 * 86 * @deprecated Use {@link TextUtils#SAFE_STRING_FLAG_SINGLE_LINE} instead 87 * @hide 88 * @removed 89 */ 90 @Deprecated 91 @SystemApi 92 public static final int SAFE_LABEL_FLAG_SINGLE_LINE = SAFE_STRING_FLAG_SINGLE_LINE; 93 94 /** 95 * Return only first line of text (truncate at first newline). Cannot be set at the same time as 96 * {@link #SAFE_LABEL_FLAG_SINGLE_LINE}. 97 * 98 * @see #loadSafeLabel(PackageManager, float, int) 99 * 100 * @deprecated Use {@link TextUtils#SAFE_STRING_FLAG_FIRST_LINE} instead 101 * @hide 102 * @removed 103 */ 104 @Deprecated 105 @SystemApi 106 public static final int SAFE_LABEL_FLAG_FIRST_LINE = SAFE_STRING_FLAG_FIRST_LINE; 107 108 private static volatile boolean sForceSafeLabels = false; 109 110 /** 111 * Always use {@link #loadSafeLabel safe labels} when calling {@link #loadLabel}. 112 * 113 * @hide 114 */ 115 @SystemApi forceSafeLabels()116 public static void forceSafeLabels() { 117 sForceSafeLabels = true; 118 } 119 120 /** 121 * Public name of this item. From the "android:name" attribute. 122 */ 123 public String name; 124 125 /** 126 * Name of the package that this item is in. 127 */ 128 public String packageName; 129 130 /** 131 * A string resource identifier (in the package's resources) of this 132 * component's label. From the "label" attribute or, if not set, 0. 133 */ 134 public int labelRes; 135 136 /** 137 * The string provided in the AndroidManifest file, if any. You 138 * probably don't want to use this. You probably want 139 * {@link PackageManager#getApplicationLabel} 140 */ 141 public CharSequence nonLocalizedLabel; 142 143 /** 144 * A drawable resource identifier (in the package's resources) of this 145 * component's icon. From the "icon" attribute or, if not set, 0. 146 */ 147 public int icon; 148 149 /** 150 * A drawable resource identifier (in the package's resources) of this 151 * component's banner. From the "banner" attribute or, if not set, 0. 152 */ 153 public int banner; 154 155 /** 156 * A drawable resource identifier (in the package's resources) of this 157 * component's logo. Logos may be larger/wider than icons and are 158 * displayed by certain UI elements in place of a name or name/icon 159 * combination. From the "logo" attribute or, if not set, 0. 160 */ 161 public int logo; 162 163 /** 164 * Additional meta-data associated with this component. This field 165 * will only be filled in if you set the 166 * {@link PackageManager#GET_META_DATA} flag when requesting the info. 167 */ 168 public Bundle metaData; 169 170 /** 171 * If different of UserHandle.USER_NULL, The icon of this item will represent that user. 172 * @hide 173 */ 174 public int showUserIcon; 175 PackageItemInfo()176 public PackageItemInfo() { 177 showUserIcon = UserHandle.USER_NULL; 178 } 179 PackageItemInfo(PackageItemInfo orig)180 public PackageItemInfo(PackageItemInfo orig) { 181 name = orig.name; 182 if (name != null) name = name.trim(); 183 packageName = orig.packageName; 184 labelRes = orig.labelRes; 185 nonLocalizedLabel = orig.nonLocalizedLabel; 186 if (nonLocalizedLabel != null) nonLocalizedLabel = nonLocalizedLabel.toString().trim(); 187 icon = orig.icon; 188 banner = orig.banner; 189 logo = orig.logo; 190 metaData = orig.metaData; 191 showUserIcon = orig.showUserIcon; 192 } 193 194 /** 195 * Retrieve the current textual label associated with this item. This 196 * will call back on the given PackageManager to load the label from 197 * the application. 198 * 199 * @param pm A PackageManager from which the label can be loaded; usually 200 * the PackageManager from which you originally retrieved this item. 201 * 202 * @return Returns a CharSequence containing the item's label. If the 203 * item does not have a label, its name is returned. 204 */ loadLabel(@onNull PackageManager pm)205 public @NonNull CharSequence loadLabel(@NonNull PackageManager pm) { 206 if (sForceSafeLabels && !Objects.equals(packageName, ActivityThread.currentPackageName())) { 207 return loadSafeLabel(pm, DEFAULT_MAX_LABEL_SIZE_PX, SAFE_STRING_FLAG_TRIM 208 | SAFE_STRING_FLAG_FIRST_LINE); 209 } else { 210 return loadUnsafeLabel(pm); 211 } 212 } 213 214 /** {@hide} */ loadUnsafeLabel(PackageManager pm)215 public CharSequence loadUnsafeLabel(PackageManager pm) { 216 if (nonLocalizedLabel != null) { 217 return nonLocalizedLabel; 218 } 219 if (labelRes != 0) { 220 CharSequence label = pm.getText(packageName, labelRes, getApplicationInfo()); 221 if (label != null) { 222 return label.toString().trim(); 223 } 224 } 225 if (name != null) { 226 return name; 227 } 228 return packageName; 229 } 230 231 /** 232 * @hide 233 * @deprecated use loadSafeLabel(PackageManager, float, int) instead 234 */ 235 @SystemApi 236 @Deprecated loadSafeLabel(@onNull PackageManager pm)237 public @NonNull CharSequence loadSafeLabel(@NonNull PackageManager pm) { 238 return loadSafeLabel(pm, DEFAULT_MAX_LABEL_SIZE_PX, SAFE_STRING_FLAG_TRIM 239 | SAFE_STRING_FLAG_FIRST_LINE); 240 } 241 242 /** 243 * Calls {@link TextUtils#makeSafeForPresentation} for the label of this item. 244 * 245 * <p>For parameters see {@link TextUtils#makeSafeForPresentation}. 246 * 247 * @hide 248 */ 249 @SystemApi loadSafeLabel(@onNull PackageManager pm, @FloatRange(from = 0) float ellipsizeDip, @TextUtils.SafeStringFlags int flags)250 public @NonNull CharSequence loadSafeLabel(@NonNull PackageManager pm, 251 @FloatRange(from = 0) float ellipsizeDip, @TextUtils.SafeStringFlags int flags) { 252 Objects.requireNonNull(pm); 253 254 return makeSafeForPresentation(loadUnsafeLabel(pm).toString(), MAX_SAFE_LABEL_LENGTH, 255 ellipsizeDip, flags); 256 } 257 258 /** 259 * Retrieve the current graphical icon associated with this item. This 260 * will call back on the given PackageManager to load the icon from 261 * the application. 262 * 263 * @param pm A PackageManager from which the icon can be loaded; usually 264 * the PackageManager from which you originally retrieved this item. 265 * 266 * @return Returns a Drawable containing the item's icon. If the 267 * item does not have an icon, the item's default icon is returned 268 * such as the default activity icon. 269 */ loadIcon(PackageManager pm)270 public Drawable loadIcon(PackageManager pm) { 271 return pm.loadItemIcon(this, getApplicationInfo()); 272 } 273 274 /** 275 * Retrieve the current graphical icon associated with this item without 276 * the addition of a work badge if applicable. 277 * This will call back on the given PackageManager to load the icon from 278 * the application. 279 * 280 * @param pm A PackageManager from which the icon can be loaded; usually 281 * the PackageManager from which you originally retrieved this item. 282 * 283 * @return Returns a Drawable containing the item's icon. If the 284 * item does not have an icon, the item's default icon is returned 285 * such as the default activity icon. 286 */ loadUnbadgedIcon(PackageManager pm)287 public Drawable loadUnbadgedIcon(PackageManager pm) { 288 return pm.loadUnbadgedItemIcon(this, getApplicationInfo()); 289 } 290 291 /** 292 * Retrieve the current graphical banner associated with this item. This 293 * will call back on the given PackageManager to load the banner from 294 * the application. 295 * 296 * @param pm A PackageManager from which the banner can be loaded; usually 297 * the PackageManager from which you originally retrieved this item. 298 * 299 * @return Returns a Drawable containing the item's banner. If the item 300 * does not have a banner, this method will return null. 301 */ loadBanner(PackageManager pm)302 public Drawable loadBanner(PackageManager pm) { 303 if (banner != 0) { 304 Drawable dr = pm.getDrawable(packageName, banner, getApplicationInfo()); 305 if (dr != null) { 306 return dr; 307 } 308 } 309 return loadDefaultBanner(pm); 310 } 311 312 /** 313 * Retrieve the default graphical icon associated with this item. 314 * 315 * @param pm A PackageManager from which the icon can be loaded; usually 316 * the PackageManager from which you originally retrieved this item. 317 * 318 * @return Returns a Drawable containing the item's default icon 319 * such as the default activity icon. 320 * 321 * @hide 322 */ loadDefaultIcon(PackageManager pm)323 public Drawable loadDefaultIcon(PackageManager pm) { 324 return pm.getDefaultActivityIcon(); 325 } 326 327 /** 328 * Retrieve the default graphical banner associated with this item. 329 * 330 * @param pm A PackageManager from which the banner can be loaded; usually 331 * the PackageManager from which you originally retrieved this item. 332 * 333 * @return Returns a Drawable containing the item's default banner 334 * or null if no default logo is available. 335 * 336 * @hide 337 */ loadDefaultBanner(PackageManager pm)338 protected Drawable loadDefaultBanner(PackageManager pm) { 339 return null; 340 } 341 342 /** 343 * Retrieve the current graphical logo associated with this item. This 344 * will call back on the given PackageManager to load the logo from 345 * the application. 346 * 347 * @param pm A PackageManager from which the logo can be loaded; usually 348 * the PackageManager from which you originally retrieved this item. 349 * 350 * @return Returns a Drawable containing the item's logo. If the item 351 * does not have a logo, this method will return null. 352 */ loadLogo(PackageManager pm)353 public Drawable loadLogo(PackageManager pm) { 354 if (logo != 0) { 355 Drawable d = pm.getDrawable(packageName, logo, getApplicationInfo()); 356 if (d != null) { 357 return d; 358 } 359 } 360 return loadDefaultLogo(pm); 361 } 362 363 /** 364 * Retrieve the default graphical logo associated with this item. 365 * 366 * @param pm A PackageManager from which the logo can be loaded; usually 367 * the PackageManager from which you originally retrieved this item. 368 * 369 * @return Returns a Drawable containing the item's default logo 370 * or null if no default logo is available. 371 * 372 * @hide 373 */ loadDefaultLogo(PackageManager pm)374 protected Drawable loadDefaultLogo(PackageManager pm) { 375 return null; 376 } 377 378 /** 379 * Load an XML resource attached to the meta-data of this item. This will 380 * retrieved the name meta-data entry, and if defined call back on the 381 * given PackageManager to load its XML file from the application. 382 * 383 * @param pm A PackageManager from which the XML can be loaded; usually 384 * the PackageManager from which you originally retrieved this item. 385 * @param name Name of the meta-date you would like to load. 386 * 387 * @return Returns an XmlPullParser you can use to parse the XML file 388 * assigned as the given meta-data. If the meta-data name is not defined 389 * or the XML resource could not be found, null is returned. 390 */ loadXmlMetaData(PackageManager pm, String name)391 public XmlResourceParser loadXmlMetaData(PackageManager pm, String name) { 392 if (metaData != null) { 393 int resid = metaData.getInt(name); 394 if (resid != 0) { 395 return pm.getXml(packageName, resid, getApplicationInfo()); 396 } 397 } 398 return null; 399 } 400 401 /** 402 * @hide Flag for dumping: include all details. 403 */ 404 public static final int DUMP_FLAG_DETAILS = 1<<0; 405 406 /** 407 * @hide Flag for dumping: include nested ApplicationInfo. 408 */ 409 public static final int DUMP_FLAG_APPLICATION = 1<<1; 410 411 /** 412 * @hide Flag for dumping: all flags to dump everything. 413 */ 414 public static final int DUMP_FLAG_ALL = DUMP_FLAG_DETAILS | DUMP_FLAG_APPLICATION; 415 dumpFront(Printer pw, String prefix)416 protected void dumpFront(Printer pw, String prefix) { 417 if (name != null) { 418 pw.println(prefix + "name=" + name); 419 } 420 pw.println(prefix + "packageName=" + packageName); 421 if (labelRes != 0 || nonLocalizedLabel != null || icon != 0 || banner != 0) { 422 pw.println(prefix + "labelRes=0x" + Integer.toHexString(labelRes) 423 + " nonLocalizedLabel=" + nonLocalizedLabel 424 + " icon=0x" + Integer.toHexString(icon) 425 + " banner=0x" + Integer.toHexString(banner)); 426 } 427 } 428 dumpBack(Printer pw, String prefix)429 protected void dumpBack(Printer pw, String prefix) { 430 // no back here 431 } 432 writeToParcel(Parcel dest, int parcelableFlags)433 public void writeToParcel(Parcel dest, int parcelableFlags) { 434 dest.writeString8(name); 435 dest.writeString8(packageName); 436 dest.writeInt(labelRes); 437 TextUtils.writeToParcel(nonLocalizedLabel, dest, parcelableFlags); 438 dest.writeInt(icon); 439 dest.writeInt(logo); 440 dest.writeBundle(metaData); 441 dest.writeInt(banner); 442 dest.writeInt(showUserIcon); 443 } 444 445 /** 446 * @hide 447 */ dumpDebug(ProtoOutputStream proto, long fieldId, int dumpFlags)448 public void dumpDebug(ProtoOutputStream proto, long fieldId, int dumpFlags) { 449 long token = proto.start(fieldId); 450 if (name != null) { 451 proto.write(PackageItemInfoProto.NAME, name); 452 } 453 proto.write(PackageItemInfoProto.PACKAGE_NAME, packageName); 454 proto.write(PackageItemInfoProto.LABEL_RES, labelRes); 455 if (nonLocalizedLabel != null) { 456 proto.write(PackageItemInfoProto.NON_LOCALIZED_LABEL, nonLocalizedLabel.toString()); 457 } 458 proto.write(PackageItemInfoProto.ICON, icon); 459 proto.write(PackageItemInfoProto.BANNER, banner); 460 proto.end(token); 461 } 462 PackageItemInfo(Parcel source)463 protected PackageItemInfo(Parcel source) { 464 name = source.readString8(); 465 packageName = source.readString8(); 466 labelRes = source.readInt(); 467 nonLocalizedLabel 468 = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source); 469 icon = source.readInt(); 470 logo = source.readInt(); 471 metaData = source.readBundle(); 472 banner = source.readInt(); 473 showUserIcon = source.readInt(); 474 } 475 476 /** 477 * Get the ApplicationInfo for the application to which this item belongs, 478 * if available, otherwise returns null. 479 * 480 * @return Returns the ApplicationInfo of this item, or null if not known. 481 * 482 * @hide 483 */ getApplicationInfo()484 protected ApplicationInfo getApplicationInfo() { 485 return null; 486 } 487 488 public static class DisplayNameComparator 489 implements Comparator<PackageItemInfo> { DisplayNameComparator(PackageManager pm)490 public DisplayNameComparator(PackageManager pm) { 491 mPM = pm; 492 } 493 compare(PackageItemInfo aa, PackageItemInfo ab)494 public final int compare(PackageItemInfo aa, PackageItemInfo ab) { 495 CharSequence sa = aa.loadLabel(mPM); 496 if (sa == null) sa = aa.name; 497 CharSequence sb = ab.loadLabel(mPM); 498 if (sb == null) sb = ab.name; 499 return sCollator.compare(sa.toString(), sb.toString()); 500 } 501 502 private final Collator sCollator = Collator.getInstance(); 503 private PackageManager mPM; 504 } 505 } 506