blob: 1812575a2272d6fd0ea56e4d2ab24f543c353e90 [file] [log] [blame]
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001/*
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 */
16package android.content.pm;
17
18import android.annotation.IntDef;
19import android.annotation.NonNull;
20import android.annotation.Nullable;
21import android.content.ComponentName;
Makoto Onuki55046222016-03-08 10:49:47 -080022import android.content.ContentResolver;
Makoto Onuki6f7362d92016-03-04 13:39:41 -080023import android.content.Context;
24import android.content.Intent;
25import android.graphics.drawable.Icon;
Makoto Onuki55046222016-03-08 10:49:47 -080026import android.os.Bundle;
Makoto Onuki6f7362d92016-03-04 13:39:41 -080027import android.os.Parcel;
28import android.os.Parcelable;
29import android.os.PersistableBundle;
30import android.os.UserHandle;
31
32import com.android.internal.util.Preconditions;
33
34import java.lang.annotation.Retention;
35import java.lang.annotation.RetentionPolicy;
36
Makoto Onuki0e65d362016-03-29 14:46:50 -070037// TODO Enhance javadoc
Makoto Onuki6f7362d92016-03-04 13:39:41 -080038/**
Makoto Onuki6f7362d92016-03-04 13:39:41 -080039 *
Makoto Onuki0e65d362016-03-29 14:46:50 -070040 * Represents a shortcut from an application.
Makoto Onuki6f7362d92016-03-04 13:39:41 -080041 *
Makoto Onuki0e65d362016-03-29 14:46:50 -070042 * <p>Notes about icons:
43 * <ul>
44 * <li>If an {@link Icon} is a resource, the system keeps the package name and the resource ID.
45 * Otherwise, the bitmap is fetched when it's registered to ShortcutManager,
46 * then shrunk if necessary, and persisted.
47 * <li>The system disallows byte[] icons, because they can easily go over the binder size limit.
48 * </ul>
Makoto Onuki6f7362d92016-03-04 13:39:41 -080049 *
Makoto Onuki0e65d362016-03-29 14:46:50 -070050 * @see {@link ShortcutManager}.
Makoto Onuki6f7362d92016-03-04 13:39:41 -080051 */
Jeff Sharkey70168dd2016-03-30 21:47:16 -060052public final class ShortcutInfo implements Parcelable {
Makoto Onuki6f7362d92016-03-04 13:39:41 -080053 /* @hide */
54 public static final int FLAG_DYNAMIC = 1 << 0;
55
56 /* @hide */
57 public static final int FLAG_PINNED = 1 << 1;
58
59 /* @hide */
60 public static final int FLAG_HAS_ICON_RES = 1 << 2;
61
62 /* @hide */
63 public static final int FLAG_HAS_ICON_FILE = 1 << 3;
64
Makoto Onuki55046222016-03-08 10:49:47 -080065 /* @hide */
66 public static final int FLAG_KEY_FIELDS_ONLY = 1 << 4;
67
Makoto Onuki6f7362d92016-03-04 13:39:41 -080068 /** @hide */
69 @IntDef(flag = true,
70 value = {
71 FLAG_DYNAMIC,
72 FLAG_PINNED,
73 FLAG_HAS_ICON_RES,
74 FLAG_HAS_ICON_FILE,
Makoto Onuki55046222016-03-08 10:49:47 -080075 FLAG_KEY_FIELDS_ONLY,
Makoto Onuki6f7362d92016-03-04 13:39:41 -080076 })
77 @Retention(RetentionPolicy.SOURCE)
78 public @interface ShortcutFlags {}
79
80 // Cloning options.
81
82 /* @hide */
83 private static final int CLONE_REMOVE_ICON = 1 << 0;
84
85 /* @hide */
86 private static final int CLONE_REMOVE_INTENT = 1 << 1;
87
88 /* @hide */
89 public static final int CLONE_REMOVE_NON_KEY_INFO = 1 << 2;
90
91 /* @hide */
92 public static final int CLONE_REMOVE_FOR_CREATOR = CLONE_REMOVE_ICON;
93
94 /* @hide */
95 public static final int CLONE_REMOVE_FOR_LAUNCHER = CLONE_REMOVE_ICON | CLONE_REMOVE_INTENT;
96
97 /** @hide */
98 @IntDef(flag = true,
99 value = {
100 CLONE_REMOVE_ICON,
101 CLONE_REMOVE_INTENT,
102 CLONE_REMOVE_NON_KEY_INFO,
103 CLONE_REMOVE_FOR_CREATOR,
104 CLONE_REMOVE_FOR_LAUNCHER
105 })
106 @Retention(RetentionPolicy.SOURCE)
107 public @interface CloneFlags {}
108
109 private final String mId;
110
111 @NonNull
112 private final String mPackageName;
113
114 @Nullable
115 private ComponentName mActivityComponent;
116
117 @Nullable
118 private Icon mIcon;
119
120 @NonNull
121 private String mTitle;
122
Makoto Onukie3ae7ec2016-03-29 15:45:25 -0700123 @Nullable
124 private String mText;
125
Makoto Onuki55046222016-03-08 10:49:47 -0800126 /**
127 * Intent *with extras removed*.
128 */
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800129 @NonNull
130 private Intent mIntent;
131
Makoto Onuki55046222016-03-08 10:49:47 -0800132 /**
133 * Extras for the intent.
134 */
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800135 @NonNull
136 private PersistableBundle mIntentPersistableExtras;
137
138 private int mWeight;
139
140 @Nullable
141 private PersistableBundle mExtras;
142
143 private long mLastChangedTimestamp;
144
145 // Internal use only.
146 @ShortcutFlags
147 private int mFlags;
148
149 // Internal use only.
150 private int mIconResourceId;
151
152 // Internal use only.
153 @Nullable
154 private String mBitmapPath;
155
156 private ShortcutInfo(Builder b) {
157 mId = Preconditions.checkStringNotEmpty(b.mId, "Shortcut ID must be provided");
158
159 // Note we can't do other null checks here because SM.updateShortcuts() takes partial
160 // information.
161 mPackageName = b.mContext.getPackageName();
162 mActivityComponent = b.mActivityComponent;
163 mIcon = b.mIcon;
164 mTitle = b.mTitle;
Makoto Onukie3ae7ec2016-03-29 15:45:25 -0700165 mText = b.mText;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800166 mIntent = b.mIntent;
Makoto Onuki7a6a05f2016-03-10 17:01:08 -0800167 if (mIntent != null) {
168 final Bundle intentExtras = mIntent.getExtras();
169 if (intentExtras != null) {
170 mIntent.replaceExtras((Bundle) null);
171 mIntentPersistableExtras = new PersistableBundle(intentExtras);
172 }
Makoto Onuki55046222016-03-08 10:49:47 -0800173 }
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800174 mWeight = b.mWeight;
175 mExtras = b.mExtras;
176 updateTimestamp();
177 }
178
179 /**
180 * Throws if any of the mandatory fields is not set.
181 *
182 * @hide
183 */
184 public void enforceMandatoryFields() {
Makoto Onukie3ae7ec2016-03-29 15:45:25 -0700185 Preconditions.checkStringNotEmpty(mId, "Shortcut ID must be provided");
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800186 Preconditions.checkStringNotEmpty(mTitle, "Shortcut title must be provided");
187 Preconditions.checkNotNull(mIntent, "Shortcut Intent must be provided");
188 }
189
190 /**
191 * Copy constructor.
192 */
193 private ShortcutInfo(ShortcutInfo source, @CloneFlags int cloneFlags) {
194 mId = source.mId;
195 mPackageName = source.mPackageName;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800196 mFlags = source.mFlags;
197 mLastChangedTimestamp = source.mLastChangedTimestamp;
198
199 if ((cloneFlags & CLONE_REMOVE_NON_KEY_INFO) == 0) {
Makoto Onuki55046222016-03-08 10:49:47 -0800200 mActivityComponent = source.mActivityComponent;
201
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800202 if ((cloneFlags & CLONE_REMOVE_ICON) == 0) {
203 mIcon = source.mIcon;
Makoto Onuki7a6a05f2016-03-10 17:01:08 -0800204 mBitmapPath = source.mBitmapPath;
Makoto Onukie3ae7ec2016-03-29 15:45:25 -0700205 mIconResourceId = source.mIconResourceId;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800206 }
207
208 mTitle = source.mTitle;
Makoto Onukie3ae7ec2016-03-29 15:45:25 -0700209 mText = source.mText;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800210 if ((cloneFlags & CLONE_REMOVE_INTENT) == 0) {
211 mIntent = source.mIntent;
212 mIntentPersistableExtras = source.mIntentPersistableExtras;
213 }
214 mWeight = source.mWeight;
215 mExtras = source.mExtras;
Makoto Onuki55046222016-03-08 10:49:47 -0800216 } else {
217 // Set this bit.
218 mFlags |= FLAG_KEY_FIELDS_ONLY;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800219 }
220 }
221
222 /**
223 * Copy a {@link ShortcutInfo}, optionally removing fields.
224 * @hide
225 */
226 public ShortcutInfo clone(@CloneFlags int cloneFlags) {
227 return new ShortcutInfo(this, cloneFlags);
228 }
229
230 /**
231 * Copy non-null/zero fields from another {@link ShortcutInfo}. Only "public" information
232 * will be overwritten. The timestamp will be updated.
233 *
234 * - Flags will not change
235 * - mBitmapPath will not change
236 * - Current time will be set to timestamp
237 *
238 * @hide
239 */
240 public void copyNonNullFieldsFrom(ShortcutInfo source) {
Makoto Onuki7a6a05f2016-03-10 17:01:08 -0800241 Preconditions.checkState(mId.equals(source.mId), "ID must match");
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800242 Preconditions.checkState(mPackageName.equals(source.mPackageName),
Makoto Onuki7a6a05f2016-03-10 17:01:08 -0800243 "Package name must match");
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800244
245 if (source.mActivityComponent != null) {
246 mActivityComponent = source.mActivityComponent;
247 }
248
249 if (source.mIcon != null) {
250 mIcon = source.mIcon;
251 }
252 if (source.mTitle != null) {
253 mTitle = source.mTitle;
254 }
Makoto Onukie3ae7ec2016-03-29 15:45:25 -0700255 if (source.mText != null) {
256 mText = source.mText;
257 }
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800258 if (source.mIntent != null) {
259 mIntent = source.mIntent;
260 mIntentPersistableExtras = source.mIntentPersistableExtras;
261 }
262 if (source.mWeight != 0) {
263 mWeight = source.mWeight;
264 }
265 if (source.mExtras != null) {
266 mExtras = source.mExtras;
267 }
268
269 updateTimestamp();
270 }
271
272 /**
Makoto Onuki55046222016-03-08 10:49:47 -0800273 * @hide
274 */
275 public static Icon validateIcon(Icon icon) {
276 switch (icon.getType()) {
277 case Icon.TYPE_RESOURCE:
278 case Icon.TYPE_BITMAP:
279 break; // OK
280 case Icon.TYPE_URI:
281 if (ContentResolver.SCHEME_CONTENT.equals(icon.getUri().getScheme())) {
282 break;
283 }
284 // Note "file:" is not supported, because depending on the path, system server
285 // cannot access it. // TODO Revisit "file:" icon support
286
287 // fall through
288 default:
289 throw getInvalidIconException();
290 }
291 if (icon.hasTint()) {
292 // TODO support it
293 throw new IllegalArgumentException("Icons with tints are not supported");
294 }
295
296 return icon;
297 }
298
299 /** @hide */
300 public static IllegalArgumentException getInvalidIconException() {
301 return new IllegalArgumentException("Unsupported icon type:"
302 +" only bitmap, resource and content URI are supported");
303 }
304
305 /**
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800306 * Builder class for {@link ShortcutInfo} objects.
307 */
308 public static class Builder {
309 private final Context mContext;
310
311 private String mId;
312
313 private ComponentName mActivityComponent;
314
315 private Icon mIcon;
316
317 private String mTitle;
318
Makoto Onukie3ae7ec2016-03-29 15:45:25 -0700319 private String mText;
320
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800321 private Intent mIntent;
322
323 private int mWeight;
324
325 private PersistableBundle mExtras;
326
327 /** Constructor. */
328 public Builder(Context context) {
329 mContext = context;
330 }
331
332 /**
333 * Sets the ID of the shortcut. This is a mandatory field.
334 */
335 @NonNull
336 public Builder setId(@NonNull String id) {
337 mId = Preconditions.checkStringNotEmpty(id, "id");
338 return this;
339 }
340
341 /**
Makoto Onuki55046222016-03-08 10:49:47 -0800342 * Optionally sets the target activity. If it's not set, and if the caller application
343 * has multiple launcher icons, this shortcut will be shown on all those icons.
344 * If it's set, this shortcut will be only shown on this activity.
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800345 */
346 @NonNull
347 public Builder setActivityComponent(@NonNull ComponentName activityComponent) {
348 mActivityComponent = Preconditions.checkNotNull(activityComponent, "activityComponent");
349 return this;
350 }
351
352 /**
353 * Optionally sets an icon.
354 *
Makoto Onuki55046222016-03-08 10:49:47 -0800355 * <ul>
356 * <li>Tints are not supported.
357 * <li>Bitmaps, resources and "content:" URIs are supported.
358 * <li>"content:" URI will be fetched when a shortcut is registered to
359 * {@link ShortcutManager}. Changing the content from the same URI later will
360 * not be reflected to launcher icons.
361 * </ul>
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800362 *
Makoto Onuki55046222016-03-08 10:49:47 -0800363 * <p>For performance reasons, icons will <b>NOT</b> be available on instances
364 * returned by {@link ShortcutManager} or {@link LauncherApps}. Launcher applications
365 * need to use {@link LauncherApps#getShortcutIconFd(ShortcutInfo, UserHandle)}
366 * and {@link LauncherApps#getShortcutIconResId(ShortcutInfo, UserHandle)}.
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800367 */
368 @NonNull
369 public Builder setIcon(Icon icon) {
Makoto Onuki55046222016-03-08 10:49:47 -0800370 mIcon = validateIcon(icon);
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800371 return this;
372 }
373
374 /**
375 * Sets the title of a shortcut. This is a mandatory field.
Makoto Onuki0e65d362016-03-29 14:46:50 -0700376 *
377 * <p>This field is intended for a concise description of a shortcut displayed under
378 * an icon. The recommend max length is 10 characters.
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800379 */
380 @NonNull
381 public Builder setTitle(@NonNull String title) {
382 mTitle = Preconditions.checkStringNotEmpty(title, "title");
383 return this;
384 }
385
386 /**
Makoto Onukie3ae7ec2016-03-29 15:45:25 -0700387 * Sets the text of a shortcut. This is an optional field.
Makoto Onuki0e65d362016-03-29 14:46:50 -0700388 *
389 * <p>This field is intended to be more descriptive than the shortcut title.
390 * The recommend max length is 25 characters.
Makoto Onukie3ae7ec2016-03-29 15:45:25 -0700391 */
392 @NonNull
393 public Builder setText(@NonNull String text) {
394 mText = Preconditions.checkStringNotEmpty(text, "text");
395 return this;
396 }
397
398 /**
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800399 * Sets the intent of a shortcut. This is a mandatory field. The extras must only contain
400 * persistable information. (See {@link PersistableBundle}).
401 */
402 @NonNull
403 public Builder setIntent(@NonNull Intent intent) {
404 mIntent = Preconditions.checkNotNull(intent, "intent");
405 return this;
406 }
407
408 /**
Makoto Onuki55046222016-03-08 10:49:47 -0800409 * Optionally sets the weight of a shortcut, which will be used by the launcher for sorting.
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800410 * The larger the weight, the more "important" a shortcut is.
411 */
412 @NonNull
413 public Builder setWeight(int weight) {
414 mWeight = weight;
415 return this;
416 }
417
418 /**
Makoto Onuki55046222016-03-08 10:49:47 -0800419 * Optional values that applications can set. Applications can store any meta-data of
420 * shortcuts in this, and retrieve later from {@link ShortcutInfo#getExtras()}.
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800421 */
422 @NonNull
423 public Builder setExtras(@NonNull PersistableBundle extras) {
424 mExtras = extras;
425 return this;
426 }
427
428 /**
429 * Creates a {@link ShortcutInfo} instance.
430 */
431 @NonNull
432 public ShortcutInfo build() {
433 return new ShortcutInfo(this);
434 }
435 }
436
437 /**
438 * Return the ID of the shortcut.
439 */
440 @NonNull
441 public String getId() {
442 return mId;
443 }
444
445 /**
Makoto Onuki55046222016-03-08 10:49:47 -0800446 * Return the package name of the creator application.
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800447 */
448 @NonNull
449 public String getPackageName() {
450 return mPackageName;
451 }
452
453 /**
454 * Return the target activity, which may be null, in which case the shortcut is not associated
455 * with a specific activity.
456 */
457 @Nullable
458 public ComponentName getActivityComponent() {
459 return mActivityComponent;
460 }
461
462 /**
463 * Icon.
464 *
465 * For performance reasons, this will <b>NOT</b> be available when an instance is returned
466 * by {@link ShortcutManager} or {@link LauncherApps}. A launcher application needs to use
Makoto Onuki55046222016-03-08 10:49:47 -0800467 * other APIs in LauncherApps to fetch the bitmap.
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800468 *
469 * @hide
470 */
471 @Nullable
472 public Icon getIcon() {
473 return mIcon;
474 }
475
476 /**
477 * Return the shortcut title.
Makoto Onuki55046222016-03-08 10:49:47 -0800478 *
479 * <p>All shortcuts must have a non-empty title, but this method will return null when
480 * {@link #hasKeyFieldsOnly()} is true.
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800481 */
Makoto Onuki55046222016-03-08 10:49:47 -0800482 @Nullable
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800483 public String getTitle() {
484 return mTitle;
485 }
486
487 /**
Makoto Onukie3ae7ec2016-03-29 15:45:25 -0700488 * Return the shortcut text.
489 */
490 @Nullable
491 public String getText() {
492 return mText;
493 }
494
495 /**
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800496 * Return the intent.
Makoto Onuki55046222016-03-08 10:49:47 -0800497 *
498 * <p>All shortcuts must have an intent, but this method will return null when
499 * {@link #hasKeyFieldsOnly()} is true.
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800500 */
Makoto Onuki55046222016-03-08 10:49:47 -0800501 @Nullable
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800502 public Intent getIntent() {
Makoto Onuki55046222016-03-08 10:49:47 -0800503 if (mIntent == null) {
504 return null;
505 }
506 final Intent intent = new Intent(mIntent);
507 intent.replaceExtras(
508 mIntentPersistableExtras != null ? new Bundle(mIntentPersistableExtras) : null);
509 return intent;
510 }
511
512 /**
513 * Return "raw" intent, which is the original intent without the extras.
514 * @hide
515 */
516 @Nullable
517 public Intent getIntentNoExtras() {
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800518 return mIntent;
519 }
520
Makoto Onuki55046222016-03-08 10:49:47 -0800521 /**
522 * The extras in the intent. We convert extras into {@link PersistableBundle} so we can
523 * persist them.
524 * @hide
525 */
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800526 @Nullable
527 public PersistableBundle getIntentPersistableExtras() {
528 return mIntentPersistableExtras;
529 }
530
531 /**
532 * Return the weight of a shortcut, which will be used by Launcher for sorting.
533 * The larger the weight, the more "important" a shortcut is.
534 */
535 public int getWeight() {
536 return mWeight;
537 }
538
539 /**
540 * Optional values that application can set.
541 */
542 @Nullable
543 public PersistableBundle getExtras() {
544 return mExtras;
545 }
546
547 /**
548 * Last time when any of the fields was updated.
549 */
550 public long getLastChangedTimestamp() {
551 return mLastChangedTimestamp;
552 }
553
554 /** @hide */
555 @ShortcutFlags
556 public int getFlags() {
557 return mFlags;
558 }
559
560 /** @hide*/
Makoto Onukide667372016-03-15 14:29:20 -0700561 public void replaceFlags(@ShortcutFlags int flags) {
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800562 mFlags = flags;
563 }
564
565 /** @hide*/
566 public void addFlags(@ShortcutFlags int flags) {
567 mFlags |= flags;
568 }
569
570 /** @hide*/
571 public void clearFlags(@ShortcutFlags int flags) {
572 mFlags &= ~flags;
573 }
574
575 /** @hide*/
576 public boolean hasFlags(@ShortcutFlags int flags) {
577 return (mFlags & flags) == flags;
578 }
579
580 /** Return whether a shortcut is dynamic. */
581 public boolean isDynamic() {
582 return hasFlags(FLAG_DYNAMIC);
583 }
584
585 /** Return whether a shortcut is pinned. */
586 public boolean isPinned() {
587 return hasFlags(FLAG_PINNED);
588 }
589
590 /**
591 * Return whether a shortcut's icon is a resource in the owning package.
592 *
593 * @see LauncherApps#getShortcutIconResId(ShortcutInfo, UserHandle)
594 */
595 public boolean hasIconResource() {
596 return hasFlags(FLAG_HAS_ICON_RES);
597 }
598
599 /**
600 * Return whether a shortcut's icon is stored as a file.
601 *
602 * @see LauncherApps#getShortcutIconFd(ShortcutInfo, UserHandle)
603 */
604 public boolean hasIconFile() {
605 return hasFlags(FLAG_HAS_ICON_FILE);
606 }
607
Makoto Onuki55046222016-03-08 10:49:47 -0800608 /**
609 * Return whether a shortcut only contains "key" information only or not. If true, only the
610 * following fields are available.
611 * <ul>
612 * <li>{@link #getId()}
613 * <li>{@link #getPackageName()}
614 * <li>{@link #getLastChangedTimestamp()}
615 * <li>{@link #isDynamic()}
616 * <li>{@link #isPinned()}
617 * <li>{@link #hasIconResource()}
618 * <li>{@link #hasIconFile()}
619 * </ul>
620 */
621 public boolean hasKeyFieldsOnly() {
622 return hasFlags(FLAG_KEY_FIELDS_ONLY);
623 }
624
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800625 /** @hide */
626 public void updateTimestamp() {
627 mLastChangedTimestamp = System.currentTimeMillis();
628 }
629
630 /** @hide */
631 // VisibleForTesting
632 public void setTimestamp(long value) {
633 mLastChangedTimestamp = value;
634 }
635
636 /** @hide */
Makoto Onuki55046222016-03-08 10:49:47 -0800637 public void clearIcon() {
638 mIcon = null;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800639 }
640
641 /** @hide */
Makoto Onuki55046222016-03-08 10:49:47 -0800642 public void setIconResourceId(int iconResourceId) {
643 mIconResourceId = iconResourceId;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800644 }
645
646 /** @hide */
647 public int getIconResourceId() {
648 return mIconResourceId;
649 }
650
651 /** @hide */
652 public String getBitmapPath() {
653 return mBitmapPath;
654 }
655
656 /** @hide */
657 public void setBitmapPath(String bitmapPath) {
658 mBitmapPath = bitmapPath;
659 }
660
661 private ShortcutInfo(Parcel source) {
662 final ClassLoader cl = getClass().getClassLoader();
663
664 mId = source.readString();
665 mPackageName = source.readString();
666 mActivityComponent = source.readParcelable(cl);
667 mIcon = source.readParcelable(cl);
668 mTitle = source.readString();
Makoto Onukie3ae7ec2016-03-29 15:45:25 -0700669 mText = source.readString();
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800670 mIntent = source.readParcelable(cl);
671 mIntentPersistableExtras = source.readParcelable(cl);
672 mWeight = source.readInt();
673 mExtras = source.readParcelable(cl);
674 mLastChangedTimestamp = source.readLong();
675 mFlags = source.readInt();
676 mIconResourceId = source.readInt();
677 mBitmapPath = source.readString();
678 }
679
680 @Override
681 public void writeToParcel(Parcel dest, int flags) {
682 dest.writeString(mId);
683 dest.writeString(mPackageName);
684 dest.writeParcelable(mActivityComponent, flags);
685 dest.writeParcelable(mIcon, flags);
686 dest.writeString(mTitle);
Makoto Onukie3ae7ec2016-03-29 15:45:25 -0700687 dest.writeString(mText);
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800688 dest.writeParcelable(mIntent, flags);
689 dest.writeParcelable(mIntentPersistableExtras, flags);
690 dest.writeInt(mWeight);
691 dest.writeParcelable(mExtras, flags);
692 dest.writeLong(mLastChangedTimestamp);
693 dest.writeInt(mFlags);
694 dest.writeInt(mIconResourceId);
695 dest.writeString(mBitmapPath);
696 }
697
698 public static final Creator<ShortcutInfo> CREATOR =
699 new Creator<ShortcutInfo>() {
700 public ShortcutInfo createFromParcel(Parcel source) {
701 return new ShortcutInfo(source);
702 }
703 public ShortcutInfo[] newArray(int size) {
704 return new ShortcutInfo[size];
705 }
706 };
707
708 @Override
709 public int describeContents() {
710 return 0;
711 }
712
713 /**
714 * Return a string representation, intended for logging. Some fields will be retracted.
715 */
716 @Override
717 public String toString() {
718 return toStringInner(/* secure =*/ true, /* includeInternalData =*/ false);
719 }
720
721 /** @hide */
722 public String toInsecureString() {
723 return toStringInner(/* secure =*/ false, /* includeInternalData =*/ true);
724 }
725
726 private String toStringInner(boolean secure, boolean includeInternalData) {
727 final StringBuilder sb = new StringBuilder();
728 sb.append("ShortcutInfo {");
729
730 sb.append("id=");
731 sb.append(secure ? "***" : mId);
732
733 sb.append(", packageName=");
734 sb.append(mPackageName);
735
736 if (isDynamic()) {
737 sb.append(", dynamic");
738 }
739 if (isPinned()) {
740 sb.append(", pinned");
741 }
742
743 sb.append(", activity=");
744 sb.append(mActivityComponent);
745
746 sb.append(", title=");
747 sb.append(secure ? "***" : mTitle);
748
Makoto Onukie3ae7ec2016-03-29 15:45:25 -0700749 sb.append(", text=");
750 sb.append(secure ? "***" : mText);
751
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800752 sb.append(", icon=");
753 sb.append(mIcon);
754
755 sb.append(", weight=");
756 sb.append(mWeight);
757
758 sb.append(", timestamp=");
759 sb.append(mLastChangedTimestamp);
760
761 sb.append(", intent=");
762 sb.append(mIntent);
763
764 sb.append(", intentExtras=");
765 sb.append(secure ? "***" : mIntentPersistableExtras);
766
767 sb.append(", extras=");
768 sb.append(mExtras);
769
Makoto Onuki55046222016-03-08 10:49:47 -0800770 sb.append(", flags=");
771 sb.append(mFlags);
772
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800773 if (includeInternalData) {
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800774
775 sb.append(", iconRes=");
776 sb.append(mIconResourceId);
777
778 sb.append(", bitmapPath=");
779 sb.append(mBitmapPath);
780 }
781
782 sb.append("}");
783 return sb.toString();
784 }
785
786 /** @hide */
787 public ShortcutInfo(String id, String packageName, ComponentName activityComponent,
Makoto Onukie3ae7ec2016-03-29 15:45:25 -0700788 Icon icon, String title, String text, Intent intent,
789 PersistableBundle intentPersistableExtras,
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800790 int weight, PersistableBundle extras, long lastChangedTimestamp,
791 int flags, int iconResId, String bitmapPath) {
792 mId = id;
793 mPackageName = packageName;
794 mActivityComponent = activityComponent;
795 mIcon = icon;
796 mTitle = title;
Makoto Onukie3ae7ec2016-03-29 15:45:25 -0700797 mText = text;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800798 mIntent = intent;
799 mIntentPersistableExtras = intentPersistableExtras;
800 mWeight = weight;
801 mExtras = extras;
802 mLastChangedTimestamp = lastChangedTimestamp;
803 mFlags = flags;
804 mIconResourceId = iconResId;
805 mBitmapPath = bitmapPath;
806 }
807}