1 /* 2 * Copyright (C) 2016 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 package android.content.pm; 17 18 import android.annotation.IntDef; 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.annotation.UserIdInt; 22 import android.content.ComponentName; 23 import android.content.Context; 24 import android.content.Intent; 25 import android.graphics.drawable.Icon; 26 import android.os.Bundle; 27 import android.os.Parcel; 28 import android.os.Parcelable; 29 import android.os.PersistableBundle; 30 import android.os.UserHandle; 31 import android.util.ArraySet; 32 33 import com.android.internal.util.Preconditions; 34 35 import java.lang.annotation.Retention; 36 import java.lang.annotation.RetentionPolicy; 37 import java.util.Set; 38 39 // TODO Enhance javadoc 40 /** 41 * 42 * Represents a shortcut from an application. 43 * 44 * <p>Notes about icons: 45 * <ul> 46 * <li>If an {@link Icon} is a resource, the system keeps the package name and the resource ID. 47 * Otherwise, the bitmap is fetched when it's registered to ShortcutManager, 48 * then shrunk if necessary, and persisted. 49 * <li>The system disallows byte[] icons, because they can easily go over the binder size limit. 50 * </ul> 51 * 52 * @see {@link ShortcutManager}. 53 * 54 * @hide 55 */ 56 public final class ShortcutInfo implements Parcelable { 57 /* @hide */ 58 public static final int FLAG_DYNAMIC = 1 << 0; 59 60 /* @hide */ 61 public static final int FLAG_PINNED = 1 << 1; 62 63 /* @hide */ 64 public static final int FLAG_HAS_ICON_RES = 1 << 2; 65 66 /* @hide */ 67 public static final int FLAG_HAS_ICON_FILE = 1 << 3; 68 69 /* @hide */ 70 public static final int FLAG_KEY_FIELDS_ONLY = 1 << 4; 71 72 /** @hide */ 73 @IntDef(flag = true, 74 value = { 75 FLAG_DYNAMIC, 76 FLAG_PINNED, 77 FLAG_HAS_ICON_RES, 78 FLAG_HAS_ICON_FILE, 79 FLAG_KEY_FIELDS_ONLY, 80 }) 81 @Retention(RetentionPolicy.SOURCE) 82 public @interface ShortcutFlags {} 83 84 // Cloning options. 85 86 /* @hide */ 87 private static final int CLONE_REMOVE_ICON = 1 << 0; 88 89 /* @hide */ 90 private static final int CLONE_REMOVE_INTENT = 1 << 1; 91 92 /* @hide */ 93 public static final int CLONE_REMOVE_NON_KEY_INFO = 1 << 2; 94 95 /* @hide */ 96 public static final int CLONE_REMOVE_FOR_CREATOR = CLONE_REMOVE_ICON; 97 98 /* @hide */ 99 public static final int CLONE_REMOVE_FOR_LAUNCHER = CLONE_REMOVE_ICON | CLONE_REMOVE_INTENT; 100 101 /** @hide */ 102 @IntDef(flag = true, 103 value = { 104 CLONE_REMOVE_ICON, 105 CLONE_REMOVE_INTENT, 106 CLONE_REMOVE_NON_KEY_INFO, 107 CLONE_REMOVE_FOR_CREATOR, 108 CLONE_REMOVE_FOR_LAUNCHER 109 }) 110 @Retention(RetentionPolicy.SOURCE) 111 public @interface CloneFlags {} 112 113 /** 114 * Shortcut category for 115 */ 116 public static final String SHORTCUT_CATEGORY_CONVERSATION = "android.shortcut.conversation"; 117 118 private final String mId; 119 120 @NonNull 121 private final String mPackageName; 122 123 @Nullable 124 private ComponentName mActivityComponent; 125 126 @Nullable 127 private Icon mIcon; 128 129 @NonNull 130 private String mTitle; 131 132 @Nullable 133 private String mText; 134 135 @NonNull 136 private ArraySet<String> mCategories; 137 138 /** 139 * Intent *with extras removed*. 140 */ 141 @NonNull 142 private Intent mIntent; 143 144 /** 145 * Extras for the intent. 146 */ 147 @NonNull 148 private PersistableBundle mIntentPersistableExtras; 149 150 private int mWeight; 151 152 @Nullable 153 private PersistableBundle mExtras; 154 155 private long mLastChangedTimestamp; 156 157 // Internal use only. 158 @ShortcutFlags 159 private int mFlags; 160 161 // Internal use only. 162 private int mIconResourceId; 163 164 // Internal use only. 165 @Nullable 166 private String mBitmapPath; 167 168 private final int mUserId; 169 170 private ShortcutInfo(Builder b) { 171 mUserId = b.mContext.getUserId(); 172 173 mId = Preconditions.checkStringNotEmpty(b.mId, "Shortcut ID must be provided"); 174 175 // Note we can't do other null checks here because SM.updateShortcuts() takes partial 176 // information. 177 mPackageName = b.mContext.getPackageName(); 178 mActivityComponent = b.mActivityComponent; 179 mIcon = b.mIcon; 180 mTitle = b.mTitle; 181 mText = b.mText; 182 mCategories = clone(b.mCategories); 183 mIntent = b.mIntent; 184 if (mIntent != null) { 185 final Bundle intentExtras = mIntent.getExtras(); 186 if (intentExtras != null) { 187 mIntent.replaceExtras((Bundle) null); 188 mIntentPersistableExtras = new PersistableBundle(intentExtras); 189 } 190 } 191 mWeight = b.mWeight; 192 mExtras = b.mExtras; 193 updateTimestamp(); 194 } 195 196 private <T> ArraySet<T> clone(Set<T> source) { 197 return (source == null) ? null : new ArraySet<>(source); 198 } 199 200 /** 201 * Throws if any of the mandatory fields is not set. 202 * 203 * @hide 204 */ 205 public void enforceMandatoryFields() { 206 Preconditions.checkStringNotEmpty(mId, "Shortcut ID must be provided"); 207 Preconditions.checkStringNotEmpty(mTitle, "Shortcut title must be provided"); 208 Preconditions.checkNotNull(mIntent, "Shortcut Intent must be provided"); 209 } 210 211 /** 212 * Copy constructor. 213 */ 214 private ShortcutInfo(ShortcutInfo source, @CloneFlags int cloneFlags) { 215 mUserId = source.mUserId; 216 mId = source.mId; 217 mPackageName = source.mPackageName; 218 mFlags = source.mFlags; 219 mLastChangedTimestamp = source.mLastChangedTimestamp; 220 221 // Just always keep it since it's cheep. 222 mIconResourceId = source.mIconResourceId; 223 224 if ((cloneFlags & CLONE_REMOVE_NON_KEY_INFO) == 0) { 225 mActivityComponent = source.mActivityComponent; 226 227 if ((cloneFlags & CLONE_REMOVE_ICON) == 0) { 228 mIcon = source.mIcon; 229 mBitmapPath = source.mBitmapPath; 230 } 231 232 mTitle = source.mTitle; 233 mText = source.mText; 234 mCategories = clone(source.mCategories); 235 if ((cloneFlags & CLONE_REMOVE_INTENT) == 0) { 236 mIntent = source.mIntent; 237 mIntentPersistableExtras = source.mIntentPersistableExtras; 238 } 239 mWeight = source.mWeight; 240 mExtras = source.mExtras; 241 } else { 242 // Set this bit. 243 mFlags |= FLAG_KEY_FIELDS_ONLY; 244 } 245 } 246 247 /** 248 * Copy a {@link ShortcutInfo}, optionally removing fields. 249 * @hide 250 */ 251 public ShortcutInfo clone(@CloneFlags int cloneFlags) { 252 return new ShortcutInfo(this, cloneFlags); 253 } 254 255 /** 256 * Copy non-null/zero fields from another {@link ShortcutInfo}. Only "public" information 257 * will be overwritten. The timestamp will be updated. 258 * 259 * - Flags will not change 260 * - mBitmapPath will not change 261 * - Current time will be set to timestamp 262 * 263 * @hide 264 */ 265 public void copyNonNullFieldsFrom(ShortcutInfo source) { 266 Preconditions.checkState(mUserId == source.mUserId, "Owner User ID must match"); 267 Preconditions.checkState(mId.equals(source.mId), "ID must match"); 268 Preconditions.checkState(mPackageName.equals(source.mPackageName), 269 "Package name must match"); 270 271 if (source.mActivityComponent != null) { 272 mActivityComponent = source.mActivityComponent; 273 } 274 275 if (source.mIcon != null) { 276 mIcon = source.mIcon; 277 } 278 if (source.mTitle != null) { 279 mTitle = source.mTitle; 280 } 281 if (source.mText != null) { 282 mText = source.mText; 283 } 284 if (source.mCategories != null) { 285 mCategories = clone(source.mCategories); 286 } 287 if (source.mIntent != null) { 288 mIntent = source.mIntent; 289 mIntentPersistableExtras = source.mIntentPersistableExtras; 290 } 291 if (source.mWeight != 0) { 292 mWeight = source.mWeight; 293 } 294 if (source.mExtras != null) { 295 mExtras = source.mExtras; 296 } 297 298 updateTimestamp(); 299 } 300 301 /** 302 * @hide 303 */ 304 public static Icon validateIcon(Icon icon) { 305 switch (icon.getType()) { 306 case Icon.TYPE_RESOURCE: 307 case Icon.TYPE_BITMAP: 308 break; // OK 309 default: 310 throw getInvalidIconException(); 311 } 312 if (icon.hasTint()) { 313 // TODO support it 314 throw new IllegalArgumentException("Icons with tints are not supported"); 315 } 316 317 return icon; 318 } 319 320 /** @hide */ 321 public static IllegalArgumentException getInvalidIconException() { 322 return new IllegalArgumentException("Unsupported icon type:" 323 +" only bitmap, resource and content URI are supported"); 324 } 325 326 /** 327 * Builder class for {@link ShortcutInfo} objects. 328 */ 329 public static class Builder { 330 private final Context mContext; 331 332 private String mId; 333 334 private ComponentName mActivityComponent; 335 336 private Icon mIcon; 337 338 private String mTitle; 339 340 private String mText; 341 342 private Set<String> mCategories; 343 344 private Intent mIntent; 345 346 private int mWeight; 347 348 private PersistableBundle mExtras; 349 350 /** Constructor. */ 351 public Builder(Context context) { 352 mContext = context; 353 } 354 355 /** 356 * Sets the ID of the shortcut. This is a mandatory field. 357 */ 358 @NonNull 359 public Builder setId(@NonNull String id) { 360 mId = Preconditions.checkStringNotEmpty(id, "id"); 361 return this; 362 } 363 364 /** 365 * Optionally sets the target activity. If it's not set, and if the caller application 366 * has multiple launcher icons, this shortcut will be shown on all those icons. 367 * If it's set, this shortcut will be only shown on this activity. 368 * 369 * <p>The package name of the target activity must match the package name of the shortcut 370 * publisher. 371 * 372 * <p>This has nothing to do with the activity that this shortcut will launch. This is 373 * a hint to the launcher app about which launcher icon to associate this shortcut with. 374 */ 375 @NonNull 376 public Builder setActivityComponent(@NonNull ComponentName activityComponent) { 377 mActivityComponent = Preconditions.checkNotNull(activityComponent, "activityComponent"); 378 return this; 379 } 380 381 /** 382 * Optionally sets an icon. 383 * 384 * <ul> 385 * <li>Tints set by {@link Icon#setTint} or {@link Icon#setTintList} are not supported. 386 * <li>Bitmaps and resources are supported, but "content:" URIs are not supported. 387 * </ul> 388 * 389 * <p>For performance reasons, icons will <b>NOT</b> be available on instances 390 * returned by {@link ShortcutManager} or {@link LauncherApps}. Launcher applications 391 * can use {@link ShortcutInfo#getIconResourceId()} if {@link #hasIconResource()} is true. 392 * Otherwise, if {@link #hasIconFile()} is true, use 393 * {@link LauncherApps#getShortcutIconFd} to load the image. 394 */ 395 @NonNull 396 public Builder setIcon(Icon icon) { 397 mIcon = validateIcon(icon); 398 return this; 399 } 400 401 /** 402 * Sets the title of a shortcut. This is a mandatory field. 403 * 404 * <p>This field is intended for a concise description of a shortcut displayed under 405 * an icon. The recommend max length is 10 characters. 406 */ 407 @NonNull 408 public Builder setTitle(@NonNull String title) { 409 mTitle = Preconditions.checkStringNotEmpty(title, "title"); 410 return this; 411 } 412 413 /** 414 * Sets the text of a shortcut. This is an optional field. 415 * 416 * <p>This field is intended to be more descriptive than the shortcut title. 417 * The recommend max length is 25 characters. 418 */ 419 @NonNull 420 public Builder setText(@NonNull String text) { 421 mText = Preconditions.checkStringNotEmpty(text, "text"); 422 return this; 423 } 424 425 /** 426 * Sets categories for a shortcut. Launcher applications may use this information to 427 * categorise shortcuts. 428 * 429 * @see #SHORTCUT_CATEGORY_CONVERSATION 430 */ 431 @NonNull 432 public Builder setCategories(Set<String> categories) { 433 mCategories = categories; 434 return this; 435 } 436 437 /** 438 * Sets the intent of a shortcut. This is a mandatory field. The extras must only contain 439 * persistable information. (See {@link PersistableBundle}). 440 */ 441 @NonNull 442 public Builder setIntent(@NonNull Intent intent) { 443 mIntent = Preconditions.checkNotNull(intent, "intent"); 444 return this; 445 } 446 447 /** 448 * Optionally sets the weight of a shortcut, which will be used by the launcher for sorting. 449 * The larger the weight, the more "important" a shortcut is. 450 */ 451 @NonNull 452 public Builder setWeight(int weight) { 453 mWeight = weight; 454 return this; 455 } 456 457 /** 458 * Optional values that applications can set. Applications can store any meta-data of 459 * shortcuts in this, and retrieve later from {@link ShortcutInfo#getExtras()}. 460 */ 461 @NonNull 462 public Builder setExtras(@NonNull PersistableBundle extras) { 463 mExtras = extras; 464 return this; 465 } 466 467 /** 468 * Creates a {@link ShortcutInfo} instance. 469 */ 470 @NonNull 471 public ShortcutInfo build() { 472 return new ShortcutInfo(this); 473 } 474 } 475 476 /** 477 * Return the ID of the shortcut. 478 */ 479 @NonNull 480 public String getId() { 481 return mId; 482 } 483 484 /** 485 * Return the package name of the creator application. 486 */ 487 @NonNull 488 public String getPackageName() { 489 return mPackageName; 490 } 491 492 /** 493 * Return the target activity, which may be null, in which case the shortcut is not associated 494 * with a specific activity. 495 * 496 * <p>This has nothing to do with the activity that this shortcut will launch. This is 497 * a hint to the launcher app that on which launcher icon this shortcut should be shown. 498 * 499 * @see Builder#setActivityComponent 500 */ 501 @Nullable 502 public ComponentName getActivityComponent() { 503 return mActivityComponent; 504 } 505 506 /** 507 * Icon. 508 * 509 * For performance reasons, this will <b>NOT</b> be available when an instance is returned 510 * by {@link ShortcutManager} or {@link LauncherApps}. A launcher application needs to use 511 * other APIs in LauncherApps to fetch the bitmap. 512 * 513 * @hide 514 */ 515 @Nullable 516 public Icon getIcon() { 517 return mIcon; 518 } 519 520 /** 521 * Return the shortcut title. 522 * 523 * <p>All shortcuts must have a non-empty title, but this method will return null when 524 * {@link #hasKeyFieldsOnly()} is true. 525 */ 526 @Nullable 527 public String getTitle() { 528 return mTitle; 529 } 530 531 /** 532 * Return the shortcut text. 533 */ 534 @Nullable 535 public String getText() { 536 return mText; 537 } 538 539 /** 540 * Return the categories. 541 */ 542 @Nullable 543 public Set<String> getCategories() { 544 return mCategories; 545 } 546 547 /** 548 * Return the intent. 549 * 550 * <p>All shortcuts must have an intent, but this method will return null when 551 * {@link #hasKeyFieldsOnly()} is true. 552 * 553 * <p>Launcher apps <b>cannot</b> see the intent. If a {@link ShortcutInfo} is obtained via 554 * {@link LauncherApps}, then this method will always return null. Launcher apps can only 555 * start a shortcut intent with {@link LauncherApps#startShortcut}. 556 */ 557 @Nullable 558 public Intent getIntent() { 559 if (mIntent == null) { 560 return null; 561 } 562 final Intent intent = new Intent(mIntent); 563 intent.replaceExtras( 564 mIntentPersistableExtras != null ? new Bundle(mIntentPersistableExtras) : null); 565 return intent; 566 } 567 568 /** 569 * Return "raw" intent, which is the original intent without the extras. 570 * @hide 571 */ 572 @Nullable 573 public Intent getIntentNoExtras() { 574 return mIntent; 575 } 576 577 /** 578 * The extras in the intent. We convert extras into {@link PersistableBundle} so we can 579 * persist them. 580 * @hide 581 */ 582 @Nullable 583 public PersistableBundle getIntentPersistableExtras() { 584 return mIntentPersistableExtras; 585 } 586 587 /** 588 * Return the weight of a shortcut, which will be used by Launcher for sorting. 589 * The larger the weight, the more "important" a shortcut is. 590 */ 591 public int getWeight() { 592 return mWeight; 593 } 594 595 /** 596 * Optional values that application can set. 597 */ 598 @Nullable 599 public PersistableBundle getExtras() { 600 return mExtras; 601 } 602 603 /** @hide */ 604 public int getUserId() { 605 return mUserId; 606 } 607 608 /** 609 * {@link UserHandle} on which the publisher created shortcuts. 610 */ 611 public UserHandle getUserHandle() { 612 return UserHandle.of(mUserId); 613 } 614 615 /** 616 * Last time when any of the fields was updated. 617 */ 618 public long getLastChangedTimestamp() { 619 return mLastChangedTimestamp; 620 } 621 622 /** @hide */ 623 @ShortcutFlags 624 public int getFlags() { 625 return mFlags; 626 } 627 628 /** @hide*/ 629 public void replaceFlags(@ShortcutFlags int flags) { 630 mFlags = flags; 631 } 632 633 /** @hide*/ 634 public void addFlags(@ShortcutFlags int flags) { 635 mFlags |= flags; 636 } 637 638 /** @hide*/ 639 public void clearFlags(@ShortcutFlags int flags) { 640 mFlags &= ~flags; 641 } 642 643 /** @hide*/ 644 public boolean hasFlags(@ShortcutFlags int flags) { 645 return (mFlags & flags) == flags; 646 } 647 648 /** Return whether a shortcut is dynamic. */ 649 public boolean isDynamic() { 650 return hasFlags(FLAG_DYNAMIC); 651 } 652 653 /** Return whether a shortcut is pinned. */ 654 public boolean isPinned() { 655 return hasFlags(FLAG_PINNED); 656 } 657 658 /** 659 * Return whether a shortcut's icon is a resource in the owning package. 660 * 661 * @see LauncherApps#getShortcutIconResId(ShortcutInfo) 662 */ 663 public boolean hasIconResource() { 664 return hasFlags(FLAG_HAS_ICON_RES); 665 } 666 667 /** 668 * Return whether a shortcut's icon is stored as a file. 669 * 670 * @see LauncherApps#getShortcutIconFd(ShortcutInfo) 671 */ 672 public boolean hasIconFile() { 673 return hasFlags(FLAG_HAS_ICON_FILE); 674 } 675 676 /** 677 * Return whether a shortcut only contains "key" information only or not. If true, only the 678 * following fields are available. 679 * <ul> 680 * <li>{@link #getId()} 681 * <li>{@link #getPackageName()} 682 * <li>{@link #getLastChangedTimestamp()} 683 * <li>{@link #isDynamic()} 684 * <li>{@link #isPinned()} 685 * <li>{@link #hasIconResource()} 686 * <li>{@link #hasIconFile()} 687 * </ul> 688 */ 689 public boolean hasKeyFieldsOnly() { 690 return hasFlags(FLAG_KEY_FIELDS_ONLY); 691 } 692 693 /** @hide */ 694 public void updateTimestamp() { 695 mLastChangedTimestamp = System.currentTimeMillis(); 696 } 697 698 /** @hide */ 699 // VisibleForTesting 700 public void setTimestamp(long value) { 701 mLastChangedTimestamp = value; 702 } 703 704 /** @hide */ 705 public void clearIcon() { 706 mIcon = null; 707 } 708 709 /** @hide */ 710 public void setIconResourceId(int iconResourceId) { 711 mIconResourceId = iconResourceId; 712 } 713 714 /** 715 * Get the resource ID for the icon, valid only when {@link #hasIconResource()} } is true. 716 */ 717 public int getIconResourceId() { 718 return mIconResourceId; 719 } 720 721 /** @hide */ 722 public String getBitmapPath() { 723 return mBitmapPath; 724 } 725 726 /** @hide */ 727 public void setBitmapPath(String bitmapPath) { 728 mBitmapPath = bitmapPath; 729 } 730 731 private ShortcutInfo(Parcel source) { 732 final ClassLoader cl = getClass().getClassLoader(); 733 734 mUserId = source.readInt(); 735 mId = source.readString(); 736 mPackageName = source.readString(); 737 mActivityComponent = source.readParcelable(cl); 738 mIcon = source.readParcelable(cl); 739 mTitle = source.readString(); 740 mText = source.readString(); 741 mIntent = source.readParcelable(cl); 742 mIntentPersistableExtras = source.readParcelable(cl); 743 mWeight = source.readInt(); 744 mExtras = source.readParcelable(cl); 745 mLastChangedTimestamp = source.readLong(); 746 mFlags = source.readInt(); 747 mIconResourceId = source.readInt(); 748 mBitmapPath = source.readString(); 749 750 int N = source.readInt(); 751 if (N == 0) { 752 mCategories = null; 753 } else { 754 mCategories = new ArraySet<>(N); 755 for (int i = 0; i < N; i++) { 756 mCategories.add(source.readString().intern()); 757 } 758 } 759 } 760 761 @Override 762 public void writeToParcel(Parcel dest, int flags) { 763 dest.writeInt(mUserId); 764 dest.writeString(mId); 765 dest.writeString(mPackageName); 766 dest.writeParcelable(mActivityComponent, flags); 767 dest.writeParcelable(mIcon, flags); 768 dest.writeString(mTitle); 769 dest.writeString(mText); 770 771 dest.writeParcelable(mIntent, flags); 772 dest.writeParcelable(mIntentPersistableExtras, flags); 773 dest.writeInt(mWeight); 774 dest.writeParcelable(mExtras, flags); 775 dest.writeLong(mLastChangedTimestamp); 776 dest.writeInt(mFlags); 777 dest.writeInt(mIconResourceId); 778 dest.writeString(mBitmapPath); 779 780 if (mCategories != null) { 781 final int N = mCategories.size(); 782 dest.writeInt(N); 783 for (int i = 0; i < N; i++) { 784 dest.writeString(mCategories.valueAt(i)); 785 } 786 } else { 787 dest.writeInt(0); 788 } 789 } 790 791 public static final Creator<ShortcutInfo> CREATOR = 792 new Creator<ShortcutInfo>() { 793 public ShortcutInfo createFromParcel(Parcel source) { 794 return new ShortcutInfo(source); 795 } 796 public ShortcutInfo[] newArray(int size) { 797 return new ShortcutInfo[size]; 798 } 799 }; 800 801 @Override 802 public int describeContents() { 803 return 0; 804 } 805 806 /** 807 * Return a string representation, intended for logging. Some fields will be retracted. 808 */ 809 @Override 810 public String toString() { 811 return toStringInner(/* secure =*/ true, /* includeInternalData =*/ false); 812 } 813 814 /** @hide */ 815 public String toInsecureString() { 816 return toStringInner(/* secure =*/ false, /* includeInternalData =*/ true); 817 } 818 819 private String toStringInner(boolean secure, boolean includeInternalData) { 820 final StringBuilder sb = new StringBuilder(); 821 sb.append("ShortcutInfo {"); 822 823 sb.append("id="); 824 sb.append(secure ? "***" : mId); 825 826 sb.append(", packageName="); 827 sb.append(mPackageName); 828 829 if (isDynamic()) { 830 sb.append(", dynamic"); 831 } 832 if (isPinned()) { 833 sb.append(", pinned"); 834 } 835 836 sb.append(", activity="); 837 sb.append(mActivityComponent); 838 839 sb.append(", title="); 840 sb.append(secure ? "***" : mTitle); 841 842 sb.append(", text="); 843 sb.append(secure ? "***" : mText); 844 845 sb.append(", categories="); 846 sb.append(mCategories); 847 848 sb.append(", icon="); 849 sb.append(mIcon); 850 851 sb.append(", weight="); 852 sb.append(mWeight); 853 854 sb.append(", timestamp="); 855 sb.append(mLastChangedTimestamp); 856 857 sb.append(", intent="); 858 sb.append(mIntent); 859 860 sb.append(", intentExtras="); 861 sb.append(secure ? "***" : mIntentPersistableExtras); 862 863 sb.append(", extras="); 864 sb.append(mExtras); 865 866 sb.append(", flags="); 867 sb.append(mFlags); 868 869 if (includeInternalData) { 870 871 sb.append(", iconRes="); 872 sb.append(mIconResourceId); 873 874 sb.append(", bitmapPath="); 875 sb.append(mBitmapPath); 876 } 877 878 sb.append("}"); 879 return sb.toString(); 880 } 881 882 /** @hide */ 883 public ShortcutInfo( 884 @UserIdInt int userId, String id, String packageName, ComponentName activityComponent, 885 Icon icon, String title, String text, Set<String> categories, Intent intent, 886 PersistableBundle intentPersistableExtras, 887 int weight, PersistableBundle extras, long lastChangedTimestamp, 888 int flags, int iconResId, String bitmapPath) { 889 mUserId = userId; 890 mId = id; 891 mPackageName = packageName; 892 mActivityComponent = activityComponent; 893 mIcon = icon; 894 mTitle = title; 895 mText = text; 896 mCategories = clone(categories); 897 mIntent = intent; 898 mIntentPersistableExtras = intentPersistableExtras; 899 mWeight = weight; 900 mExtras = extras; 901 mLastChangedTimestamp = lastChangedTimestamp; 902 mFlags = flags; 903 mIconResourceId = iconResId; 904 mBitmapPath = bitmapPath; 905 } 906 } 907