blob: e674b8b7fd3d82cf40c39efa013e7f9c7058cb92 [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;
Mehdi Alizadeh88873652019-02-04 14:16:46 -080021import android.annotation.SystemApi;
Makoto Onukia4f89b12017-10-05 10:37:55 -070022import android.annotation.TestApi;
Mathew Inwood5c0d3542018-08-14 13:54:31 +010023import android.annotation.UnsupportedAppUsage;
Makoto Onukiabe84422016-04-07 09:41:19 -070024import android.annotation.UserIdInt;
Mehdi Alizadeh14242af2018-12-20 20:11:35 -080025import android.app.Person;
Makoto Onuki347a6bd2016-07-19 11:13:08 -070026import android.app.TaskStackBuilder;
Makoto Onuki6f7362d92016-03-04 13:39:41 -080027import android.content.ComponentName;
28import android.content.Context;
29import android.content.Intent;
Makoto Onuki4a910962016-07-07 13:57:34 -070030import android.content.pm.LauncherApps.ShortcutQuery;
Makoto Onuki20c95f82016-05-11 16:51:01 -070031import android.content.res.Resources;
Makoto Onuki157b1622016-06-02 16:13:10 -070032import android.content.res.Resources.NotFoundException;
Makoto Onuki4a910962016-07-07 13:57:34 -070033import android.graphics.Bitmap;
Makoto Onuki6f7362d92016-03-04 13:39:41 -080034import android.graphics.drawable.Icon;
Mathew Inwood8c854f82018-09-14 12:35:36 +010035import android.os.Build;
Makoto Onuki55046222016-03-08 10:49:47 -080036import android.os.Bundle;
Makoto Onuki6f7362d92016-03-04 13:39:41 -080037import android.os.Parcel;
38import android.os.Parcelable;
39import android.os.PersistableBundle;
40import android.os.UserHandle;
Makoto Onukidf6da042016-06-16 09:51:40 -070041import android.text.TextUtils;
Makoto Onukibe73a802016-04-15 14:46:35 -070042import android.util.ArraySet;
Makoto Onuki157b1622016-06-02 16:13:10 -070043import android.util.Log;
Makoto Onuki6f7362d92016-03-04 13:39:41 -080044
Makoto Onuki157b1622016-06-02 16:13:10 -070045import com.android.internal.annotations.VisibleForTesting;
Makoto Onuki6f7362d92016-03-04 13:39:41 -080046import com.android.internal.util.Preconditions;
47
48import java.lang.annotation.Retention;
49import java.lang.annotation.RetentionPolicy;
Makoto Onukib5a012f2016-06-21 11:13:53 -070050import java.util.List;
Makoto Onukibe73a802016-04-15 14:46:35 -070051import java.util.Set;
Makoto Onuki6f7362d92016-03-04 13:39:41 -080052
53/**
Kevin Hufnagle68d699d2016-10-14 19:04:51 -070054 * Represents a shortcut that can be published via {@link ShortcutManager}.
Makoto Onuki6f7362d92016-03-04 13:39:41 -080055 *
Makoto Onuki4a910962016-07-07 13:57:34 -070056 * @see ShortcutManager
Makoto Onuki6f7362d92016-03-04 13:39:41 -080057 */
Jeff Sharkey70168dd2016-03-30 21:47:16 -060058public final class ShortcutInfo implements Parcelable {
Makoto Onuki157b1622016-06-02 16:13:10 -070059 static final String TAG = "Shortcut";
60
61 private static final String RES_TYPE_STRING = "string";
62
63 private static final String ANDROID_PACKAGE_NAME = "android";
64
Makoto Onuki9e1f5592016-06-08 12:30:23 -070065 private static final int IMPLICIT_RANK_MASK = 0x7fffffff;
66
67 private static final int RANK_CHANGED_BIT = ~IMPLICIT_RANK_MASK;
68
69 /** @hide */
70 public static final int RANK_NOT_SET = Integer.MAX_VALUE;
71
Makoto Onuki157b1622016-06-02 16:13:10 -070072 /** @hide */
Makoto Onuki6f7362d92016-03-04 13:39:41 -080073 public static final int FLAG_DYNAMIC = 1 << 0;
74
Makoto Onuki157b1622016-06-02 16:13:10 -070075 /** @hide */
Makoto Onuki6f7362d92016-03-04 13:39:41 -080076 public static final int FLAG_PINNED = 1 << 1;
77
Makoto Onuki157b1622016-06-02 16:13:10 -070078 /** @hide */
Makoto Onuki6f7362d92016-03-04 13:39:41 -080079 public static final int FLAG_HAS_ICON_RES = 1 << 2;
80
Makoto Onuki157b1622016-06-02 16:13:10 -070081 /** @hide */
Makoto Onuki6f7362d92016-03-04 13:39:41 -080082 public static final int FLAG_HAS_ICON_FILE = 1 << 3;
83
Makoto Onuki157b1622016-06-02 16:13:10 -070084 /** @hide */
Makoto Onuki55046222016-03-08 10:49:47 -080085 public static final int FLAG_KEY_FIELDS_ONLY = 1 << 4;
86
Makoto Onuki157b1622016-06-02 16:13:10 -070087 /** @hide */
Makoto Onuki22fcc682016-05-17 14:52:19 -070088 public static final int FLAG_MANIFEST = 1 << 5;
Makoto Onuki20c95f82016-05-11 16:51:01 -070089
Makoto Onuki157b1622016-06-02 16:13:10 -070090 /** @hide */
Makoto Onuki20c95f82016-05-11 16:51:01 -070091 public static final int FLAG_DISABLED = 1 << 6;
92
Makoto Onuki157b1622016-06-02 16:13:10 -070093 /** @hide */
Makoto Onuki20c95f82016-05-11 16:51:01 -070094 public static final int FLAG_STRINGS_RESOLVED = 1 << 7;
95
Makoto Onuki157b1622016-06-02 16:13:10 -070096 /** @hide */
Makoto Onuki22fcc682016-05-17 14:52:19 -070097 public static final int FLAG_IMMUTABLE = 1 << 8;
98
Makoto Onuki6f7362d92016-03-04 13:39:41 -080099 /** @hide */
Hyunyoung Songe4179e22017-03-01 12:51:26 -0800100 public static final int FLAG_ADAPTIVE_BITMAP = 1 << 9;
Hyunyoung Songf281e7a2017-02-13 10:57:42 -0800101
102 /** @hide */
Makoto Onukibf563b62017-05-04 10:25:30 -0700103 public static final int FLAG_RETURNED_BY_SERVICE = 1 << 10;
104
Makoto Onuki475c3652017-05-08 14:29:03 -0700105 /** @hide When this is set, the bitmap icon is waiting to be saved. */
106 public static final int FLAG_ICON_FILE_PENDING_SAVE = 1 << 11;
107
Makoto Onukia4f89b12017-10-05 10:37:55 -0700108 /**
109 * "Shadow" shortcuts are the ones that are restored, but the owner package hasn't been
110 * installed yet.
111 * @hide
112 */
113 public static final int FLAG_SHADOW = 1 << 12;
114
Makoto Onukibf563b62017-05-04 10:25:30 -0700115 /** @hide */
Mehdi Alizadeh14242af2018-12-20 20:11:35 -0800116 public static final int FLAG_LONG_LIVED = 1 << 13;
117
118 /** @hide */
Jeff Sharkeyce8db992017-12-13 20:05:05 -0700119 @IntDef(flag = true, prefix = { "FLAG_" }, value = {
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800120 FLAG_DYNAMIC,
121 FLAG_PINNED,
122 FLAG_HAS_ICON_RES,
123 FLAG_HAS_ICON_FILE,
Makoto Onuki55046222016-03-08 10:49:47 -0800124 FLAG_KEY_FIELDS_ONLY,
Makoto Onuki22fcc682016-05-17 14:52:19 -0700125 FLAG_MANIFEST,
Makoto Onuki20c95f82016-05-11 16:51:01 -0700126 FLAG_DISABLED,
127 FLAG_STRINGS_RESOLVED,
Makoto Onuki22fcc682016-05-17 14:52:19 -0700128 FLAG_IMMUTABLE,
Hyunyoung Songe4179e22017-03-01 12:51:26 -0800129 FLAG_ADAPTIVE_BITMAP,
Makoto Onuki475c3652017-05-08 14:29:03 -0700130 FLAG_RETURNED_BY_SERVICE,
131 FLAG_ICON_FILE_PENDING_SAVE,
Mehdi Alizadeh14242af2018-12-20 20:11:35 -0800132 FLAG_SHADOW,
133 FLAG_LONG_LIVED,
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800134 })
135 @Retention(RetentionPolicy.SOURCE)
136 public @interface ShortcutFlags {}
137
138 // Cloning options.
139
Makoto Onuki157b1622016-06-02 16:13:10 -0700140 /** @hide */
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800141 private static final int CLONE_REMOVE_ICON = 1 << 0;
142
Makoto Onuki157b1622016-06-02 16:13:10 -0700143 /** @hide */
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800144 private static final int CLONE_REMOVE_INTENT = 1 << 1;
145
Makoto Onuki157b1622016-06-02 16:13:10 -0700146 /** @hide */
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800147 public static final int CLONE_REMOVE_NON_KEY_INFO = 1 << 2;
148
Makoto Onuki157b1622016-06-02 16:13:10 -0700149 /** @hide */
150 public static final int CLONE_REMOVE_RES_NAMES = 1 << 3;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800151
Makoto Onuki157b1622016-06-02 16:13:10 -0700152 /** @hide */
153 public static final int CLONE_REMOVE_FOR_CREATOR = CLONE_REMOVE_ICON | CLONE_REMOVE_RES_NAMES;
154
155 /** @hide */
156 public static final int CLONE_REMOVE_FOR_LAUNCHER = CLONE_REMOVE_ICON | CLONE_REMOVE_INTENT
157 | CLONE_REMOVE_RES_NAMES;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800158
159 /** @hide */
Makoto Onukia01f4f02016-12-15 15:58:41 -0800160 public static final int CLONE_REMOVE_FOR_LAUNCHER_APPROVAL = CLONE_REMOVE_INTENT
161 | CLONE_REMOVE_RES_NAMES;
162
163 /** @hide */
Jeff Sharkeyce8db992017-12-13 20:05:05 -0700164 @IntDef(flag = true, prefix = { "CLONE_" }, value = {
165 CLONE_REMOVE_ICON,
166 CLONE_REMOVE_INTENT,
167 CLONE_REMOVE_NON_KEY_INFO,
168 CLONE_REMOVE_RES_NAMES,
169 CLONE_REMOVE_FOR_CREATOR,
170 CLONE_REMOVE_FOR_LAUNCHER
171 })
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800172 @Retention(RetentionPolicy.SOURCE)
173 public @interface CloneFlags {}
174
Makoto Onukib6d35232016-04-04 15:57:17 -0700175 /**
Makoto Onukia4f89b12017-10-05 10:37:55 -0700176 * Shortcut is not disabled.
177 */
178 public static final int DISABLED_REASON_NOT_DISABLED = 0;
179
180 /**
181 * Shortcut has been disabled by the publisher app with the
182 * {@link ShortcutManager#disableShortcuts(List)} API.
183 */
184 public static final int DISABLED_REASON_BY_APP = 1;
185
186 /**
187 * Shortcut has been disabled due to changes to the publisher app. (e.g. a manifest shortcut
188 * no longer exists.)
189 */
190 public static final int DISABLED_REASON_APP_CHANGED = 2;
191
192 /**
Makoto Onuki5482a8e62018-01-09 10:31:08 -0800193 * Shortcut is disabled for an unknown reason.
194 */
195 public static final int DISABLED_REASON_UNKNOWN = 3;
196
197 /**
Makoto Onukia4f89b12017-10-05 10:37:55 -0700198 * A disabled reason that's equal to or bigger than this is due to backup and restore issue.
199 * A shortcut with such a reason wil be visible to the launcher, but not to the publisher.
200 * ({@link #isVisibleToPublisher()} will be false.)
201 */
202 private static final int DISABLED_REASON_RESTORE_ISSUE_START = 100;
203
204 /**
205 * Shortcut has been restored from the previous device, but the publisher app on the current
206 * device is of a lower version. The shortcut will not be usable until the app is upgraded to
207 * the same version or higher.
208 */
209 public static final int DISABLED_REASON_VERSION_LOWER = 100;
210
211 /**
212 * Shortcut has not been restored because the publisher app does not support backup and restore.
213 */
214 public static final int DISABLED_REASON_BACKUP_NOT_SUPPORTED = 101;
215
216 /**
217 * Shortcut has not been restored because the publisher app's signature has changed.
218 */
219 public static final int DISABLED_REASON_SIGNATURE_MISMATCH = 102;
220
221 /**
222 * Shortcut has not been restored for unknown reason.
223 */
224 public static final int DISABLED_REASON_OTHER_RESTORE_ISSUE = 103;
225
226 /** @hide */
Jeff Sharkeyce8db992017-12-13 20:05:05 -0700227 @IntDef(prefix = { "DISABLED_REASON_" }, value = {
Makoto Onukia4f89b12017-10-05 10:37:55 -0700228 DISABLED_REASON_NOT_DISABLED,
229 DISABLED_REASON_BY_APP,
230 DISABLED_REASON_APP_CHANGED,
Makoto Onuki5482a8e62018-01-09 10:31:08 -0800231 DISABLED_REASON_UNKNOWN,
Makoto Onukia4f89b12017-10-05 10:37:55 -0700232 DISABLED_REASON_VERSION_LOWER,
233 DISABLED_REASON_BACKUP_NOT_SUPPORTED,
234 DISABLED_REASON_SIGNATURE_MISMATCH,
235 DISABLED_REASON_OTHER_RESTORE_ISSUE,
Jeff Sharkeyce8db992017-12-13 20:05:05 -0700236 })
Makoto Onukia4f89b12017-10-05 10:37:55 -0700237 @Retention(RetentionPolicy.SOURCE)
238 public @interface DisabledReason{}
239
Makoto Onukib1588c02017-10-12 15:11:45 -0700240 /**
241 * Return a label for disabled reasons, which are *not* supposed to be shown to the user.
242 * @hide
243 */
244 public static String getDisabledReasonDebugString(@DisabledReason int disabledReason) {
Makoto Onukia4f89b12017-10-05 10:37:55 -0700245 switch (disabledReason) {
246 case DISABLED_REASON_NOT_DISABLED:
247 return "[Not disabled]";
248 case DISABLED_REASON_BY_APP:
249 return "[Disabled: by app]";
250 case DISABLED_REASON_APP_CHANGED:
251 return "[Disabled: app changed]";
252 case DISABLED_REASON_VERSION_LOWER:
253 return "[Disabled: lower version]";
254 case DISABLED_REASON_BACKUP_NOT_SUPPORTED:
255 return "[Disabled: backup not supported]";
256 case DISABLED_REASON_SIGNATURE_MISMATCH:
257 return "[Disabled: signature mismatch]";
258 case DISABLED_REASON_OTHER_RESTORE_ISSUE:
259 return "[Disabled: unknown restore issue]";
260 }
261 return "[Disabled: unknown reason:" + disabledReason + "]";
262 }
263
Makoto Onukib1588c02017-10-12 15:11:45 -0700264 /**
265 * Return a label for a disabled reason for shortcuts that are disabled due to a backup and
266 * restore issue. If the reason is not due to backup & restore, then it'll return null.
267 *
268 * This method returns localized, user-facing strings, which will be returned by
269 * {@link #getDisabledMessage()}.
270 *
271 * @hide
272 */
273 public static String getDisabledReasonForRestoreIssue(Context context,
274 @DisabledReason int disabledReason) {
275 final Resources res = context.getResources();
276
277 switch (disabledReason) {
278 case DISABLED_REASON_VERSION_LOWER:
279 return res.getString(
280 com.android.internal.R.string.shortcut_restored_on_lower_version);
281 case DISABLED_REASON_BACKUP_NOT_SUPPORTED:
282 return res.getString(
283 com.android.internal.R.string.shortcut_restore_not_supported);
284 case DISABLED_REASON_SIGNATURE_MISMATCH:
285 return res.getString(
286 com.android.internal.R.string.shortcut_restore_signature_mismatch);
287 case DISABLED_REASON_OTHER_RESTORE_ISSUE:
288 return res.getString(
289 com.android.internal.R.string.shortcut_restore_unknown_issue);
Makoto Onuki5482a8e62018-01-09 10:31:08 -0800290 case DISABLED_REASON_UNKNOWN:
291 return res.getString(
292 com.android.internal.R.string.shortcut_disabled_reason_unknown);
Makoto Onukib1588c02017-10-12 15:11:45 -0700293 }
294 return null;
295 }
296
Makoto Onukia4f89b12017-10-05 10:37:55 -0700297 /** @hide */
298 public static boolean isDisabledForRestoreIssue(@DisabledReason int disabledReason) {
299 return disabledReason >= DISABLED_REASON_RESTORE_ISSUE_START;
300 }
301
302 /**
Makoto Onuki4a910962016-07-07 13:57:34 -0700303 * Shortcut category for messaging related actions, such as chat.
Makoto Onukib6d35232016-04-04 15:57:17 -0700304 */
305 public static final String SHORTCUT_CATEGORY_CONVERSATION = "android.shortcut.conversation";
306
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800307 private final String mId;
308
309 @NonNull
310 private final String mPackageName;
311
312 @Nullable
Makoto Onuki22fcc682016-05-17 14:52:19 -0700313 private ComponentName mActivity;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800314
315 @Nullable
316 private Icon mIcon;
317
Makoto Onuki20c95f82016-05-11 16:51:01 -0700318 private int mTitleResId;
319
Makoto Onuki157b1622016-06-02 16:13:10 -0700320 private String mTitleResName;
321
Makoto Onuki20c95f82016-05-11 16:51:01 -0700322 @Nullable
Makoto Onuki22fcc682016-05-17 14:52:19 -0700323 private CharSequence mTitle;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800324
Makoto Onuki20c95f82016-05-11 16:51:01 -0700325 private int mTextResId;
326
Makoto Onuki157b1622016-06-02 16:13:10 -0700327 private String mTextResName;
328
Makoto Onukie3ae7ec2016-03-29 15:45:25 -0700329 @Nullable
Makoto Onuki22fcc682016-05-17 14:52:19 -0700330 private CharSequence mText;
Makoto Onukie3ae7ec2016-03-29 15:45:25 -0700331
Makoto Onuki20c95f82016-05-11 16:51:01 -0700332 private int mDisabledMessageResId;
333
Makoto Onuki157b1622016-06-02 16:13:10 -0700334 private String mDisabledMessageResName;
335
Makoto Onuki20c95f82016-05-11 16:51:01 -0700336 @Nullable
Makoto Onuki22fcc682016-05-17 14:52:19 -0700337 private CharSequence mDisabledMessage;
Makoto Onuki20c95f82016-05-11 16:51:01 -0700338
339 @Nullable
Makoto Onukibe73a802016-04-15 14:46:35 -0700340 private ArraySet<String> mCategories;
Makoto Onukib6d35232016-04-04 15:57:17 -0700341
Makoto Onuki55046222016-03-08 10:49:47 -0800342 /**
Makoto Onuki440a1ea2016-07-20 14:21:18 -0700343 * Intents *with extras removed*.
Makoto Onuki55046222016-03-08 10:49:47 -0800344 */
Makoto Onuki20c95f82016-05-11 16:51:01 -0700345 @Nullable
Makoto Onuki440a1ea2016-07-20 14:21:18 -0700346 private Intent[] mIntents;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800347
Makoto Onuki55046222016-03-08 10:49:47 -0800348 /**
Makoto Onuki440a1ea2016-07-20 14:21:18 -0700349 * Extras for the intents.
Makoto Onuki55046222016-03-08 10:49:47 -0800350 */
Makoto Onuki20c95f82016-05-11 16:51:01 -0700351 @Nullable
Makoto Onuki440a1ea2016-07-20 14:21:18 -0700352 private PersistableBundle[] mIntentPersistableExtrases;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800353
Mehdi Alizadeh14242af2018-12-20 20:11:35 -0800354 @Nullable
355 private Person[] mPersons;
356
Makoto Onuki20c95f82016-05-11 16:51:01 -0700357 private int mRank;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800358
Makoto Onuki9e1f5592016-06-08 12:30:23 -0700359 /**
360 * Internally used for auto-rank-adjustment.
361 *
362 * RANK_CHANGED_BIT is used to denote that the rank of a shortcut is changing.
363 * The rest of the bits are used to denote the order in which shortcuts are passed to
364 * APIs, which is used to preserve the argument order when ranks are tie.
365 */
366 private int mImplicitRank;
367
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800368 @Nullable
369 private PersistableBundle mExtras;
370
371 private long mLastChangedTimestamp;
372
373 // Internal use only.
374 @ShortcutFlags
375 private int mFlags;
376
377 // Internal use only.
Makoto Onuki157b1622016-06-02 16:13:10 -0700378 private int mIconResId;
379
380 private String mIconResName;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800381
382 // Internal use only.
383 @Nullable
384 private String mBitmapPath;
385
Makoto Onukiabe84422016-04-07 09:41:19 -0700386 private final int mUserId;
387
Makoto Onukia4f89b12017-10-05 10:37:55 -0700388 /** @hide */
389 public static final int VERSION_CODE_UNKNOWN = -1;
390
391 private int mDisabledReason;
392
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800393 private ShortcutInfo(Builder b) {
Makoto Onukiabe84422016-04-07 09:41:19 -0700394 mUserId = b.mContext.getUserId();
395
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800396 mId = Preconditions.checkStringNotEmpty(b.mId, "Shortcut ID must be provided");
397
398 // Note we can't do other null checks here because SM.updateShortcuts() takes partial
399 // information.
400 mPackageName = b.mContext.getPackageName();
Makoto Onuki22fcc682016-05-17 14:52:19 -0700401 mActivity = b.mActivity;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800402 mIcon = b.mIcon;
403 mTitle = b.mTitle;
Makoto Onuki20c95f82016-05-11 16:51:01 -0700404 mTitleResId = b.mTitleResId;
Makoto Onukie3ae7ec2016-03-29 15:45:25 -0700405 mText = b.mText;
Makoto Onuki20c95f82016-05-11 16:51:01 -0700406 mTextResId = b.mTextResId;
407 mDisabledMessage = b.mDisabledMessage;
408 mDisabledMessageResId = b.mDisabledMessageResId;
Makoto Onukidf6da042016-06-16 09:51:40 -0700409 mCategories = cloneCategories(b.mCategories);
Makoto Onuki440a1ea2016-07-20 14:21:18 -0700410 mIntents = cloneIntents(b.mIntents);
411 fixUpIntentExtras();
Mehdi Alizadeh14242af2018-12-20 20:11:35 -0800412 mPersons = clonePersons(b.mPersons);
413 if (b.mIsLongLived) {
414 setLongLived();
415 }
Makoto Onuki20c95f82016-05-11 16:51:01 -0700416 mRank = b.mRank;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800417 mExtras = b.mExtras;
418 updateTimestamp();
419 }
420
Makoto Onuki440a1ea2016-07-20 14:21:18 -0700421 /**
422 * Extract extras from {@link #mIntents} and set them to {@link #mIntentPersistableExtrases}
423 * as {@link PersistableBundle}, and remove extras from the original intents.
424 */
425 private void fixUpIntentExtras() {
426 if (mIntents == null) {
427 mIntentPersistableExtrases = null;
428 return;
429 }
430 mIntentPersistableExtrases = new PersistableBundle[mIntents.length];
431 for (int i = 0; i < mIntents.length; i++) {
432 final Intent intent = mIntents[i];
433 final Bundle extras = intent.getExtras();
434 if (extras == null) {
435 mIntentPersistableExtrases[i] = null;
436 } else {
437 mIntentPersistableExtrases[i] = new PersistableBundle(extras);
438 intent.replaceExtras((Bundle) null);
439 }
440 }
441 }
442
443 private static ArraySet<String> cloneCategories(Set<String> source) {
Makoto Onukidf6da042016-06-16 09:51:40 -0700444 if (source == null) {
445 return null;
446 }
447 final ArraySet<String> ret = new ArraySet<>(source.size());
448 for (CharSequence s : source) {
449 if (!TextUtils.isEmpty(s)) {
450 ret.add(s.toString().intern());
451 }
452 }
453 return ret;
Makoto Onukib6d35232016-04-04 15:57:17 -0700454 }
455
Makoto Onuki440a1ea2016-07-20 14:21:18 -0700456 private static Intent[] cloneIntents(Intent[] intents) {
457 if (intents == null) {
458 return null;
459 }
460 final Intent[] ret = new Intent[intents.length];
461 for (int i = 0; i < ret.length; i++) {
462 if (intents[i] != null) {
463 ret[i] = new Intent(intents[i]);
464 }
465 }
466 return ret;
467 }
468
469 private static PersistableBundle[] clonePersistableBundle(PersistableBundle[] bundle) {
470 if (bundle == null) {
471 return null;
472 }
473 final PersistableBundle[] ret = new PersistableBundle[bundle.length];
474 for (int i = 0; i < ret.length; i++) {
475 if (bundle[i] != null) {
476 ret[i] = new PersistableBundle(bundle[i]);
477 }
478 }
479 return ret;
480 }
481
Mehdi Alizadeh14242af2018-12-20 20:11:35 -0800482 private static Person[] clonePersons(Person[] persons) {
483 if (persons == null) {
484 return null;
485 }
486 final Person[] ret = new Person[persons.length];
487 for (int i = 0; i < ret.length; i++) {
488 if (persons[i] != null) {
489 // Don't need to keep the icon, remove it to save space
490 ret[i] = persons[i].toBuilder().setIcon(null).build();
491 }
492 }
493 return ret;
494 }
495
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800496 /**
497 * Throws if any of the mandatory fields is not set.
498 *
499 * @hide
500 */
Makoto Onuki106ff7a2016-12-01 10:17:57 -0800501 public void enforceMandatoryFields(boolean forPinned) {
Makoto Onukie3ae7ec2016-03-29 15:45:25 -0700502 Preconditions.checkStringNotEmpty(mId, "Shortcut ID must be provided");
Makoto Onuki106ff7a2016-12-01 10:17:57 -0800503 if (!forPinned) {
504 Preconditions.checkNotNull(mActivity, "Activity must be provided");
505 }
Makoto Onuki20c95f82016-05-11 16:51:01 -0700506 if (mTitle == null && mTitleResId == 0) {
Makoto Onukia1d38b32016-06-10 15:32:26 -0700507 throw new IllegalArgumentException("Short label must be provided");
Makoto Onuki20c95f82016-05-11 16:51:01 -0700508 }
Makoto Onuki99302b52017-03-29 12:42:26 -0700509 Preconditions.checkNotNull(mIntents, "Shortcut Intent must be provided");
510 Preconditions.checkArgument(mIntents.length > 0, "Shortcut Intent must be provided");
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800511 }
512
513 /**
514 * Copy constructor.
515 */
516 private ShortcutInfo(ShortcutInfo source, @CloneFlags int cloneFlags) {
Makoto Onukiabe84422016-04-07 09:41:19 -0700517 mUserId = source.mUserId;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800518 mId = source.mId;
519 mPackageName = source.mPackageName;
Makoto Onuki4d6b87f2016-06-17 13:47:40 -0700520 mActivity = source.mActivity;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800521 mFlags = source.mFlags;
522 mLastChangedTimestamp = source.mLastChangedTimestamp;
Makoto Onukia4f89b12017-10-05 10:37:55 -0700523 mDisabledReason = source.mDisabledReason;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800524
Makoto Onukib6d35232016-04-04 15:57:17 -0700525 // Just always keep it since it's cheep.
Makoto Onuki157b1622016-06-02 16:13:10 -0700526 mIconResId = source.mIconResId;
Makoto Onukib6d35232016-04-04 15:57:17 -0700527
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800528 if ((cloneFlags & CLONE_REMOVE_NON_KEY_INFO) == 0) {
Makoto Onuki55046222016-03-08 10:49:47 -0800529
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800530 if ((cloneFlags & CLONE_REMOVE_ICON) == 0) {
531 mIcon = source.mIcon;
Makoto Onuki7a6a05f2016-03-10 17:01:08 -0800532 mBitmapPath = source.mBitmapPath;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800533 }
534
535 mTitle = source.mTitle;
Makoto Onuki20c95f82016-05-11 16:51:01 -0700536 mTitleResId = source.mTitleResId;
Makoto Onukie3ae7ec2016-03-29 15:45:25 -0700537 mText = source.mText;
Makoto Onuki20c95f82016-05-11 16:51:01 -0700538 mTextResId = source.mTextResId;
539 mDisabledMessage = source.mDisabledMessage;
540 mDisabledMessageResId = source.mDisabledMessageResId;
Makoto Onukidf6da042016-06-16 09:51:40 -0700541 mCategories = cloneCategories(source.mCategories);
Mehdi Alizadeh14242af2018-12-20 20:11:35 -0800542 mPersons = clonePersons(source.mPersons);
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800543 if ((cloneFlags & CLONE_REMOVE_INTENT) == 0) {
Makoto Onuki440a1ea2016-07-20 14:21:18 -0700544 mIntents = cloneIntents(source.mIntents);
545 mIntentPersistableExtrases =
546 clonePersistableBundle(source.mIntentPersistableExtrases);
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800547 }
Makoto Onuki20c95f82016-05-11 16:51:01 -0700548 mRank = source.mRank;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800549 mExtras = source.mExtras;
Makoto Onuki157b1622016-06-02 16:13:10 -0700550
551 if ((cloneFlags & CLONE_REMOVE_RES_NAMES) == 0) {
552 mTitleResName = source.mTitleResName;
553 mTextResName = source.mTextResName;
554 mDisabledMessageResName = source.mDisabledMessageResName;
555 mIconResName = source.mIconResName;
556 }
Makoto Onuki55046222016-03-08 10:49:47 -0800557 } else {
558 // Set this bit.
559 mFlags |= FLAG_KEY_FIELDS_ONLY;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800560 }
561 }
562
Makoto Onuki157b1622016-06-02 16:13:10 -0700563 /**
564 * Load a string resource from the publisher app.
565 *
566 * @param resId resource ID
567 * @param defValue default value to be returned when the specified resource isn't found.
568 */
569 private CharSequence getResourceString(Resources res, int resId, CharSequence defValue) {
570 try {
571 return res.getString(resId);
572 } catch (NotFoundException e) {
573 Log.e(TAG, "Resource for ID=" + resId + " not found in package " + mPackageName);
574 return defValue;
575 }
576 }
577
578 /**
579 * Load the string resources for the text fields and set them to the actual value fields.
580 * This will set {@link #FLAG_STRINGS_RESOLVED}.
581 *
582 * @param res {@link Resources} for the publisher. Must have been loaded with
583 * {@link PackageManager#getResourcesForApplicationAsUser}.
584 *
585 * @hide
586 */
587 public void resolveResourceStrings(@NonNull Resources res) {
Makoto Onuki20c95f82016-05-11 16:51:01 -0700588 mFlags |= FLAG_STRINGS_RESOLVED;
589
590 if ((mTitleResId == 0) && (mTextResId == 0) && (mDisabledMessageResId == 0)) {
591 return; // Bail early.
592 }
Makoto Onuki20c95f82016-05-11 16:51:01 -0700593
594 if (mTitleResId != 0) {
Makoto Onuki157b1622016-06-02 16:13:10 -0700595 mTitle = getResourceString(res, mTitleResId, mTitle);
Makoto Onuki20c95f82016-05-11 16:51:01 -0700596 }
597 if (mTextResId != 0) {
Makoto Onuki157b1622016-06-02 16:13:10 -0700598 mText = getResourceString(res, mTextResId, mText);
Makoto Onuki20c95f82016-05-11 16:51:01 -0700599 }
600 if (mDisabledMessageResId != 0) {
Makoto Onuki157b1622016-06-02 16:13:10 -0700601 mDisabledMessage = getResourceString(res, mDisabledMessageResId, mDisabledMessage);
Makoto Onuki20c95f82016-05-11 16:51:01 -0700602 }
603 }
604
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800605 /**
Makoto Onuki157b1622016-06-02 16:13:10 -0700606 * Look up resource name for a given resource ID.
607 *
608 * @return a simple resource name (e.g. "text_1") when {@code withType} is false, or with the
609 * type (e.g. "string/text_1").
610 *
611 * @hide
612 */
613 @VisibleForTesting
614 public static String lookUpResourceName(@NonNull Resources res, int resId, boolean withType,
615 @NonNull String packageName) {
616 if (resId == 0) {
617 return null;
618 }
619 try {
620 final String fullName = res.getResourceName(resId);
621
622 if (ANDROID_PACKAGE_NAME.equals(getResourcePackageName(fullName))) {
623 // If it's a framework resource, the value won't change, so just return the ID
624 // value as a string.
625 return String.valueOf(resId);
626 }
627 return withType ? getResourceTypeAndEntryName(fullName)
628 : getResourceEntryName(fullName);
629 } catch (NotFoundException e) {
630 Log.e(TAG, "Resource name for ID=" + resId + " not found in package " + packageName
631 + ". Resource IDs may change when the application is upgraded, and the system"
632 + " may not be able to find the correct resource.");
633 return null;
634 }
635 }
636
637 /**
638 * Extract the package name from a fully-donated resource name.
639 * e.g. "com.android.app1:drawable/icon1" -> "com.android.app1"
640 * @hide
641 */
642 @VisibleForTesting
643 public static String getResourcePackageName(@NonNull String fullResourceName) {
644 final int p1 = fullResourceName.indexOf(':');
645 if (p1 < 0) {
646 return null;
647 }
648 return fullResourceName.substring(0, p1);
649 }
650
651 /**
652 * Extract the type name from a fully-donated resource name.
653 * e.g. "com.android.app1:drawable/icon1" -> "drawable"
654 * @hide
655 */
656 @VisibleForTesting
657 public static String getResourceTypeName(@NonNull String fullResourceName) {
658 final int p1 = fullResourceName.indexOf(':');
659 if (p1 < 0) {
660 return null;
661 }
662 final int p2 = fullResourceName.indexOf('/', p1 + 1);
663 if (p2 < 0) {
664 return null;
665 }
666 return fullResourceName.substring(p1 + 1, p2);
667 }
668
669 /**
670 * Extract the type name + the entry name from a fully-donated resource name.
671 * e.g. "com.android.app1:drawable/icon1" -> "drawable/icon1"
672 * @hide
673 */
674 @VisibleForTesting
675 public static String getResourceTypeAndEntryName(@NonNull String fullResourceName) {
676 final int p1 = fullResourceName.indexOf(':');
677 if (p1 < 0) {
678 return null;
679 }
680 return fullResourceName.substring(p1 + 1);
681 }
682
683 /**
684 * Extract the entry name from a fully-donated resource name.
685 * e.g. "com.android.app1:drawable/icon1" -> "icon1"
686 * @hide
687 */
688 @VisibleForTesting
689 public static String getResourceEntryName(@NonNull String fullResourceName) {
690 final int p1 = fullResourceName.indexOf('/');
691 if (p1 < 0) {
692 return null;
693 }
694 return fullResourceName.substring(p1 + 1);
695 }
696
697 /**
698 * Return the resource ID for a given resource ID.
699 *
700 * Basically its' a wrapper over {@link Resources#getIdentifier(String, String, String)}, except
701 * if {@code resourceName} is an integer then it'll just return its value. (Which also the
702 * aforementioned method would do internally, but not documented, so doing here explicitly.)
703 *
704 * @param res {@link Resources} for the publisher. Must have been loaded with
705 * {@link PackageManager#getResourcesForApplicationAsUser}.
706 *
707 * @hide
708 */
709 @VisibleForTesting
710 public static int lookUpResourceId(@NonNull Resources res, @Nullable String resourceName,
711 @Nullable String resourceType, String packageName) {
712 if (resourceName == null) {
713 return 0;
714 }
715 try {
716 try {
717 // It the name can be parsed as an integer, just use it.
718 return Integer.parseInt(resourceName);
719 } catch (NumberFormatException ignore) {
720 }
721
722 return res.getIdentifier(resourceName, resourceType, packageName);
723 } catch (NotFoundException e) {
724 Log.e(TAG, "Resource ID for name=" + resourceName + " not found in package "
725 + packageName);
726 return 0;
727 }
728 }
729
730 /**
731 * Look up resource names from the resource IDs for the icon res and the text fields, and fill
732 * in the resource name fields.
733 *
734 * @param res {@link Resources} for the publisher. Must have been loaded with
735 * {@link PackageManager#getResourcesForApplicationAsUser}.
736 *
737 * @hide
738 */
739 public void lookupAndFillInResourceNames(@NonNull Resources res) {
740 if ((mTitleResId == 0) && (mTextResId == 0) && (mDisabledMessageResId == 0)
741 && (mIconResId == 0)) {
742 return; // Bail early.
743 }
744
745 // We don't need types for strings because their types are always "string".
746 mTitleResName = lookUpResourceName(res, mTitleResId, /*withType=*/ false, mPackageName);
747 mTextResName = lookUpResourceName(res, mTextResId, /*withType=*/ false, mPackageName);
748 mDisabledMessageResName = lookUpResourceName(res, mDisabledMessageResId,
749 /*withType=*/ false, mPackageName);
750
751 // But icons have multiple possible types, so include the type.
752 mIconResName = lookUpResourceName(res, mIconResId, /*withType=*/ true, mPackageName);
753 }
754
755 /**
756 * Look up resource IDs from the resource names for the icon res and the text fields, and fill
757 * in the resource ID fields.
758 *
759 * This is called when an app is updated.
760 *
761 * @hide
762 */
763 public void lookupAndFillInResourceIds(@NonNull Resources res) {
764 if ((mTitleResName == null) && (mTextResName == null) && (mDisabledMessageResName == null)
765 && (mIconResName == null)) {
766 return; // Bail early.
767 }
768
769 mTitleResId = lookUpResourceId(res, mTitleResName, RES_TYPE_STRING, mPackageName);
770 mTextResId = lookUpResourceId(res, mTextResName, RES_TYPE_STRING, mPackageName);
771 mDisabledMessageResId = lookUpResourceId(res, mDisabledMessageResName, RES_TYPE_STRING,
772 mPackageName);
773
774 // mIconResName already contains the type, so the third argument is not needed.
775 mIconResId = lookUpResourceId(res, mIconResName, null, mPackageName);
776 }
777
778 /**
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800779 * Copy a {@link ShortcutInfo}, optionally removing fields.
780 * @hide
781 */
782 public ShortcutInfo clone(@CloneFlags int cloneFlags) {
783 return new ShortcutInfo(this, cloneFlags);
784 }
785
786 /**
Makoto Onuki22fcc682016-05-17 14:52:19 -0700787 * @hide
Makoto Onukia4f89b12017-10-05 10:37:55 -0700788 *
789 * @isUpdating set true if it's "update", as opposed to "replace".
Makoto Onuki22fcc682016-05-17 14:52:19 -0700790 */
Makoto Onukia4f89b12017-10-05 10:37:55 -0700791 public void ensureUpdatableWith(ShortcutInfo source, boolean isUpdating) {
792 if (isUpdating) {
793 Preconditions.checkState(isVisibleToPublisher(),
794 "[Framework BUG] Invisible shortcuts can't be updated");
795 }
Makoto Onuki22fcc682016-05-17 14:52:19 -0700796 Preconditions.checkState(mUserId == source.mUserId, "Owner User ID must match");
797 Preconditions.checkState(mId.equals(source.mId), "ID must match");
798 Preconditions.checkState(mPackageName.equals(source.mPackageName),
799 "Package name must match");
Makoto Onukia4f89b12017-10-05 10:37:55 -0700800
801 if (isVisibleToPublisher()) {
802 // Don't do this check for restore-blocked shortcuts.
803 Preconditions.checkState(!isImmutable(), "Target ShortcutInfo is immutable");
804 }
Makoto Onuki22fcc682016-05-17 14:52:19 -0700805 }
806
807 /**
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800808 * Copy non-null/zero fields from another {@link ShortcutInfo}. Only "public" information
Makoto Onuki9e1f5592016-06-08 12:30:23 -0700809 * will be overwritten. The timestamp will *not* be updated to be consistent with other
810 * setters (and also the clock is not injectable in this file).
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800811 *
812 * - Flags will not change
813 * - mBitmapPath will not change
814 * - Current time will be set to timestamp
815 *
Makoto Onuki22fcc682016-05-17 14:52:19 -0700816 * @throws IllegalStateException if source is not compatible.
817 *
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800818 * @hide
819 */
820 public void copyNonNullFieldsFrom(ShortcutInfo source) {
Makoto Onukia4f89b12017-10-05 10:37:55 -0700821 ensureUpdatableWith(source, /*isUpdating=*/ true);
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800822
Makoto Onuki22fcc682016-05-17 14:52:19 -0700823 if (source.mActivity != null) {
824 mActivity = source.mActivity;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800825 }
826
827 if (source.mIcon != null) {
828 mIcon = source.mIcon;
Makoto Onuki157b1622016-06-02 16:13:10 -0700829
830 mIconResId = 0;
831 mIconResName = null;
832 mBitmapPath = null;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800833 }
834 if (source.mTitle != null) {
835 mTitle = source.mTitle;
Makoto Onuki20c95f82016-05-11 16:51:01 -0700836 mTitleResId = 0;
Makoto Onuki157b1622016-06-02 16:13:10 -0700837 mTitleResName = null;
Makoto Onuki20c95f82016-05-11 16:51:01 -0700838 } else if (source.mTitleResId != 0) {
839 mTitle = null;
Makoto Onukieddbfec2016-05-31 17:04:34 -0700840 mTitleResId = source.mTitleResId;
Makoto Onuki157b1622016-06-02 16:13:10 -0700841 mTitleResName = null;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800842 }
Makoto Onuki157b1622016-06-02 16:13:10 -0700843
Makoto Onukie3ae7ec2016-03-29 15:45:25 -0700844 if (source.mText != null) {
845 mText = source.mText;
Makoto Onuki20c95f82016-05-11 16:51:01 -0700846 mTextResId = 0;
Makoto Onuki157b1622016-06-02 16:13:10 -0700847 mTextResName = null;
Makoto Onuki20c95f82016-05-11 16:51:01 -0700848 } else if (source.mTextResId != 0) {
849 mText = null;
850 mTextResId = source.mTextResId;
Makoto Onuki157b1622016-06-02 16:13:10 -0700851 mTextResName = null;
Makoto Onuki20c95f82016-05-11 16:51:01 -0700852 }
853 if (source.mDisabledMessage != null) {
854 mDisabledMessage = source.mDisabledMessage;
855 mDisabledMessageResId = 0;
Makoto Onuki157b1622016-06-02 16:13:10 -0700856 mDisabledMessageResName = null;
Makoto Onuki20c95f82016-05-11 16:51:01 -0700857 } else if (source.mDisabledMessageResId != 0) {
858 mDisabledMessage = null;
859 mDisabledMessageResId = source.mDisabledMessageResId;
Makoto Onuki157b1622016-06-02 16:13:10 -0700860 mDisabledMessageResName = null;
Makoto Onukie3ae7ec2016-03-29 15:45:25 -0700861 }
Makoto Onukib6d35232016-04-04 15:57:17 -0700862 if (source.mCategories != null) {
Makoto Onukidf6da042016-06-16 09:51:40 -0700863 mCategories = cloneCategories(source.mCategories);
Makoto Onukib6d35232016-04-04 15:57:17 -0700864 }
Mehdi Alizadeh14242af2018-12-20 20:11:35 -0800865 if (source.mPersons != null) {
866 mPersons = clonePersons(source.mPersons);
867 }
Makoto Onuki440a1ea2016-07-20 14:21:18 -0700868 if (source.mIntents != null) {
869 mIntents = cloneIntents(source.mIntents);
870 mIntentPersistableExtrases =
871 clonePersistableBundle(source.mIntentPersistableExtrases);
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800872 }
Makoto Onuki9e1f5592016-06-08 12:30:23 -0700873 if (source.mRank != RANK_NOT_SET) {
Makoto Onuki20c95f82016-05-11 16:51:01 -0700874 mRank = source.mRank;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800875 }
876 if (source.mExtras != null) {
877 mExtras = source.mExtras;
878 }
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800879 }
880
881 /**
Makoto Onuki55046222016-03-08 10:49:47 -0800882 * @hide
883 */
884 public static Icon validateIcon(Icon icon) {
885 switch (icon.getType()) {
886 case Icon.TYPE_RESOURCE:
887 case Icon.TYPE_BITMAP:
Hyunyoung Songe4179e22017-03-01 12:51:26 -0800888 case Icon.TYPE_ADAPTIVE_BITMAP:
Makoto Onuki55046222016-03-08 10:49:47 -0800889 break; // OK
Makoto Onuki55046222016-03-08 10:49:47 -0800890 default:
891 throw getInvalidIconException();
892 }
893 if (icon.hasTint()) {
Makoto Onuki55046222016-03-08 10:49:47 -0800894 throw new IllegalArgumentException("Icons with tints are not supported");
895 }
896
897 return icon;
898 }
899
900 /** @hide */
901 public static IllegalArgumentException getInvalidIconException() {
902 return new IllegalArgumentException("Unsupported icon type:"
Makoto Onukia97256b2016-07-15 13:23:54 -0700903 +" only the bitmap and resource types are supported");
Makoto Onuki55046222016-03-08 10:49:47 -0800904 }
905
906 /**
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800907 * Builder class for {@link ShortcutInfo} objects.
Makoto Onuki4a910962016-07-07 13:57:34 -0700908 *
909 * @see ShortcutManager
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800910 */
911 public static class Builder {
912 private final Context mContext;
913
914 private String mId;
915
Makoto Onuki22fcc682016-05-17 14:52:19 -0700916 private ComponentName mActivity;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800917
918 private Icon mIcon;
919
Makoto Onuki20c95f82016-05-11 16:51:01 -0700920 private int mTitleResId;
921
Makoto Onuki22fcc682016-05-17 14:52:19 -0700922 private CharSequence mTitle;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800923
Makoto Onuki20c95f82016-05-11 16:51:01 -0700924 private int mTextResId;
925
Makoto Onuki22fcc682016-05-17 14:52:19 -0700926 private CharSequence mText;
Makoto Onukie3ae7ec2016-03-29 15:45:25 -0700927
Makoto Onuki20c95f82016-05-11 16:51:01 -0700928 private int mDisabledMessageResId;
929
Makoto Onuki22fcc682016-05-17 14:52:19 -0700930 private CharSequence mDisabledMessage;
Makoto Onuki20c95f82016-05-11 16:51:01 -0700931
Makoto Onukibe73a802016-04-15 14:46:35 -0700932 private Set<String> mCategories;
Makoto Onukib6d35232016-04-04 15:57:17 -0700933
Makoto Onuki440a1ea2016-07-20 14:21:18 -0700934 private Intent[] mIntents;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800935
Mehdi Alizadeh14242af2018-12-20 20:11:35 -0800936 private Person[] mPersons;
937
938 private boolean mIsLongLived;
939
Makoto Onuki9e1f5592016-06-08 12:30:23 -0700940 private int mRank = RANK_NOT_SET;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800941
942 private PersistableBundle mExtras;
943
Makoto Onukib5a012f2016-06-21 11:13:53 -0700944 /**
Makoto Onuki598aca42016-07-06 16:05:03 -0700945 * Old style constructor.
946 * @hide
Makoto Onukib5a012f2016-06-21 11:13:53 -0700947 */
948 @Deprecated
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800949 public Builder(Context context) {
950 mContext = context;
951 }
952
953 /**
Makoto Onuki598aca42016-07-06 16:05:03 -0700954 * Used with the old style constructor, kept for unit tests.
955 * @hide
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800956 */
957 @NonNull
Makoto Onukib5a012f2016-06-21 11:13:53 -0700958 @Deprecated
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800959 public Builder setId(@NonNull String id) {
Makoto Onukib08790c2016-06-23 14:05:46 -0700960 mId = Preconditions.checkStringNotEmpty(id, "id cannot be empty");
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800961 return this;
962 }
963
964 /**
Makoto Onukib5a012f2016-06-21 11:13:53 -0700965 * Constructor.
966 *
967 * @param context Client context.
968 * @param id ID of the shortcut.
969 */
970 public Builder(Context context, String id) {
971 mContext = context;
Makoto Onukib08790c2016-06-23 14:05:46 -0700972 mId = Preconditions.checkStringNotEmpty(id, "id cannot be empty");
Makoto Onukib5a012f2016-06-21 11:13:53 -0700973 }
974
975 /**
Makoto Onuki4a910962016-07-07 13:57:34 -0700976 * Sets the target activity. A shortcut will be shown along with this activity's icon
977 * on the launcher.
Makoto Onukib5a012f2016-06-21 11:13:53 -0700978 *
Makoto Onukife9c9662016-07-25 15:12:23 -0700979 * When selecting a target activity, keep the following in mind:
Makoto Onuki4a910962016-07-07 13:57:34 -0700980 * <ul>
Makoto Onukife9c9662016-07-25 15:12:23 -0700981 * <li>All dynamic shortcuts must have a target activity. When a shortcut with no target
982 * activity is published using
983 * {@link ShortcutManager#addDynamicShortcuts(List)} or
984 * {@link ShortcutManager#setDynamicShortcuts(List)},
Kevin Hufnagle68d699d2016-10-14 19:04:51 -0700985 * the first main activity defined in the app's <code>AndroidManifest.xml</code>
Makoto Onukife9c9662016-07-25 15:12:23 -0700986 * file is used.
987 *
988 * <li>Only "main" activities&mdash;ones that define the {@link Intent#ACTION_MAIN}
989 * and {@link Intent#CATEGORY_LAUNCHER} intent filters&mdash;can be target
Makoto Onuki4a910962016-07-07 13:57:34 -0700990 * activities.
991 *
Kevin Hufnagle68d699d2016-10-14 19:04:51 -0700992 * <li>By default, the first main activity defined in the app's manifest is
Makoto Onukife9c9662016-07-25 15:12:23 -0700993 * the target activity.
Makoto Onuki4d36b3a2016-04-27 12:00:17 -0700994 *
Kevin Hufnagle68d699d2016-10-14 19:04:51 -0700995 * <li>A target activity must belong to the publisher app.
Makoto Onuki4a910962016-07-07 13:57:34 -0700996 * </ul>
Makoto Onuki4d36b3a2016-04-27 12:00:17 -0700997 *
Makoto Onuki4a910962016-07-07 13:57:34 -0700998 * @see ShortcutInfo#getActivity()
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800999 */
1000 @NonNull
Makoto Onuki22fcc682016-05-17 14:52:19 -07001001 public Builder setActivity(@NonNull ComponentName activity) {
Makoto Onukib08790c2016-06-23 14:05:46 -07001002 mActivity = Preconditions.checkNotNull(activity, "activity cannot be null");
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001003 return this;
1004 }
1005
1006 /**
Makoto Onuki4a910962016-07-07 13:57:34 -07001007 * Sets an icon of a shortcut.
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001008 *
Makoto Onuki4a910962016-07-07 13:57:34 -07001009 * <p>Icons are not available on {@link ShortcutInfo} instances
1010 * returned by {@link ShortcutManager} or {@link LauncherApps}. The default launcher
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001011 * app can use {@link LauncherApps#getShortcutIconDrawable(ShortcutInfo, int)}
Makoto Onukib5a012f2016-06-21 11:13:53 -07001012 * or {@link LauncherApps#getShortcutBadgedIconDrawable(ShortcutInfo, int)} to fetch
1013 * shortcut icons.
Makoto Onuki4a910962016-07-07 13:57:34 -07001014 *
1015 * <p>Tints set with {@link Icon#setTint} or {@link Icon#setTintList} are not supported
1016 * and will be ignored.
1017 *
Hyunyoung Songf281e7a2017-02-13 10:57:42 -08001018 * <p>Only icons created with {@link Icon#createWithBitmap(Bitmap)},
Hyunyoung Songe4179e22017-03-01 12:51:26 -08001019 * {@link Icon#createWithAdaptiveBitmap(Bitmap)}
Hyunyoung Songf281e7a2017-02-13 10:57:42 -08001020 * and {@link Icon#createWithResource} are supported.
Makoto Onukife9c9662016-07-25 15:12:23 -07001021 * Other types, such as URI-based icons, are not supported.
Makoto Onuki4a910962016-07-07 13:57:34 -07001022 *
1023 * @see LauncherApps#getShortcutIconDrawable(ShortcutInfo, int)
1024 * @see LauncherApps#getShortcutBadgedIconDrawable(ShortcutInfo, int)
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001025 */
1026 @NonNull
1027 public Builder setIcon(Icon icon) {
Makoto Onuki55046222016-03-08 10:49:47 -08001028 mIcon = validateIcon(icon);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001029 return this;
1030 }
1031
Makoto Onukieddbfec2016-05-31 17:04:34 -07001032 /**
1033 * @hide We don't support resource strings for dynamic shortcuts for now. (But unit tests
1034 * use it.)
1035 */
Makoto Onukib5a012f2016-06-21 11:13:53 -07001036 @Deprecated
Makoto Onukieddbfec2016-05-31 17:04:34 -07001037 public Builder setShortLabelResId(int shortLabelResId) {
1038 Preconditions.checkState(mTitle == null, "shortLabel already set");
1039 mTitleResId = shortLabelResId;
Makoto Onuki20c95f82016-05-11 16:51:01 -07001040 return this;
1041 }
1042
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001043 /**
Makoto Onukib5a012f2016-06-21 11:13:53 -07001044 * Sets the short title of a shortcut.
1045 *
Makoto Onuki4a910962016-07-07 13:57:34 -07001046 * <p>This is a mandatory field when publishing a new shortcut with
1047 * {@link ShortcutManager#addDynamicShortcuts(List)} or
1048 * {@link ShortcutManager#setDynamicShortcuts(List)}.
Makoto Onuki0e65d362016-03-29 14:46:50 -07001049 *
Makoto Onukife9c9662016-07-25 15:12:23 -07001050 * <p>This field is intended to be a concise description of a shortcut.
Makoto Onuki4a910962016-07-07 13:57:34 -07001051 *
Makoto Onukife9c9662016-07-25 15:12:23 -07001052 * <p>The recommended maximum length is 10 characters.
Makoto Onuki4a910962016-07-07 13:57:34 -07001053 *
1054 * @see ShortcutInfo#getShortLabel()
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001055 */
1056 @NonNull
Makoto Onukidf6da042016-06-16 09:51:40 -07001057 public Builder setShortLabel(@NonNull CharSequence shortLabel) {
Makoto Onukieddbfec2016-05-31 17:04:34 -07001058 Preconditions.checkState(mTitleResId == 0, "shortLabelResId already set");
Makoto Onukib08790c2016-06-23 14:05:46 -07001059 mTitle = Preconditions.checkStringNotEmpty(shortLabel, "shortLabel cannot be empty");
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001060 return this;
1061 }
1062
Makoto Onukieddbfec2016-05-31 17:04:34 -07001063 /**
1064 * @hide We don't support resource strings for dynamic shortcuts for now. (But unit tests
1065 * use it.)
1066 */
Makoto Onukib5a012f2016-06-21 11:13:53 -07001067 @Deprecated
Makoto Onukieddbfec2016-05-31 17:04:34 -07001068 public Builder setLongLabelResId(int longLabelResId) {
1069 Preconditions.checkState(mText == null, "longLabel already set");
1070 mTextResId = longLabelResId;
Makoto Onuki20c95f82016-05-11 16:51:01 -07001071 return this;
1072 }
1073
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001074 /**
Makoto Onukib5a012f2016-06-21 11:13:53 -07001075 * Sets the text of a shortcut.
Makoto Onuki0e65d362016-03-29 14:46:50 -07001076 *
Makoto Onukieddbfec2016-05-31 17:04:34 -07001077 * <p>This field is intended to be more descriptive than the shortcut title. The launcher
Makoto Onuki4a910962016-07-07 13:57:34 -07001078 * shows this instead of the short title when it has enough space.
1079 *
Makoto Onukife9c9662016-07-25 15:12:23 -07001080 * <p>The recommend maximum length is 25 characters.
Makoto Onuki4a910962016-07-07 13:57:34 -07001081 *
1082 * @see ShortcutInfo#getLongLabel()
Makoto Onukie3ae7ec2016-03-29 15:45:25 -07001083 */
1084 @NonNull
Makoto Onukidf6da042016-06-16 09:51:40 -07001085 public Builder setLongLabel(@NonNull CharSequence longLabel) {
Makoto Onukieddbfec2016-05-31 17:04:34 -07001086 Preconditions.checkState(mTextResId == 0, "longLabelResId already set");
Makoto Onukib08790c2016-06-23 14:05:46 -07001087 mText = Preconditions.checkStringNotEmpty(longLabel, "longLabel cannot be empty");
Makoto Onukie3ae7ec2016-03-29 15:45:25 -07001088 return this;
1089 }
1090
Makoto Onukieddbfec2016-05-31 17:04:34 -07001091 /** @hide -- old signature, the internal code still uses it. */
Makoto Onukib5a012f2016-06-21 11:13:53 -07001092 @Deprecated
Makoto Onukidf6da042016-06-16 09:51:40 -07001093 public Builder setTitle(@NonNull CharSequence value) {
Makoto Onukieddbfec2016-05-31 17:04:34 -07001094 return setShortLabel(value);
1095 }
1096
1097 /** @hide -- old signature, the internal code still uses it. */
Makoto Onukib5a012f2016-06-21 11:13:53 -07001098 @Deprecated
Makoto Onukieddbfec2016-05-31 17:04:34 -07001099 public Builder setTitleResId(int value) {
1100 return setShortLabelResId(value);
1101 }
1102
1103 /** @hide -- old signature, the internal code still uses it. */
Makoto Onukib5a012f2016-06-21 11:13:53 -07001104 @Deprecated
Makoto Onukidf6da042016-06-16 09:51:40 -07001105 public Builder setText(@NonNull CharSequence value) {
Makoto Onukieddbfec2016-05-31 17:04:34 -07001106 return setLongLabel(value);
1107 }
1108
1109 /** @hide -- old signature, the internal code still uses it. */
Makoto Onukib5a012f2016-06-21 11:13:53 -07001110 @Deprecated
Makoto Onukieddbfec2016-05-31 17:04:34 -07001111 public Builder setTextResId(int value) {
1112 return setLongLabelResId(value);
1113 }
1114
1115 /**
1116 * @hide We don't support resource strings for dynamic shortcuts for now. (But unit tests
1117 * use it.)
1118 */
Makoto Onukib5a012f2016-06-21 11:13:53 -07001119 @Deprecated
Makoto Onuki20c95f82016-05-11 16:51:01 -07001120 public Builder setDisabledMessageResId(int disabledMessageResId) {
1121 Preconditions.checkState(mDisabledMessage == null, "disabledMessage already set");
1122 mDisabledMessageResId = disabledMessageResId;
1123 return this;
1124 }
1125
Makoto Onuki4a910962016-07-07 13:57:34 -07001126 /**
Makoto Onukife9c9662016-07-25 15:12:23 -07001127 * Sets the message that should be shown when the user attempts to start a shortcut that
1128 * is disabled.
Makoto Onuki4a910962016-07-07 13:57:34 -07001129 *
1130 * @see ShortcutInfo#getDisabledMessage()
1131 */
Makoto Onuki20c95f82016-05-11 16:51:01 -07001132 @NonNull
Makoto Onukidf6da042016-06-16 09:51:40 -07001133 public Builder setDisabledMessage(@NonNull CharSequence disabledMessage) {
Makoto Onuki20c95f82016-05-11 16:51:01 -07001134 Preconditions.checkState(
1135 mDisabledMessageResId == 0, "disabledMessageResId already set");
1136 mDisabledMessage =
Makoto Onukib08790c2016-06-23 14:05:46 -07001137 Preconditions.checkStringNotEmpty(disabledMessage,
1138 "disabledMessage cannot be empty");
Makoto Onuki20c95f82016-05-11 16:51:01 -07001139 return this;
1140 }
1141
Makoto Onukie3ae7ec2016-03-29 15:45:25 -07001142 /**
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001143 * Sets categories for a shortcut. Launcher apps may use this information to
1144 * categorize shortcuts.
Makoto Onukib6d35232016-04-04 15:57:17 -07001145 *
1146 * @see #SHORTCUT_CATEGORY_CONVERSATION
Makoto Onuki4a910962016-07-07 13:57:34 -07001147 * @see ShortcutInfo#getCategories()
Makoto Onukib6d35232016-04-04 15:57:17 -07001148 */
1149 @NonNull
Makoto Onukibe73a802016-04-15 14:46:35 -07001150 public Builder setCategories(Set<String> categories) {
Makoto Onukib6d35232016-04-04 15:57:17 -07001151 mCategories = categories;
1152 return this;
1153 }
1154
1155 /**
Makoto Onuki0eed4412016-07-21 11:21:59 -07001156 * Sets the intent of a shortcut. Alternatively, {@link #setIntents(Intent[])} can be used
1157 * to launch an activity with other activities in the back stack.
Makoto Onuki4a910962016-07-07 13:57:34 -07001158 *
1159 * <p>This is a mandatory field when publishing a new shortcut with
1160 * {@link ShortcutManager#addDynamicShortcuts(List)} or
1161 * {@link ShortcutManager#setDynamicShortcuts(List)}.
1162 *
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001163 * <p>A shortcut can launch any intent that the publisher app has permission to
Makoto Onukife9c9662016-07-25 15:12:23 -07001164 * launch. For example, a shortcut can launch an unexported activity within the publisher
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001165 * app. A shortcut intent doesn't have to point at the target activity.
Makoto Onuki4a910962016-07-07 13:57:34 -07001166 *
Makoto Onukife9c9662016-07-25 15:12:23 -07001167 * <p>The given {@code intent} can contain extras, but these extras must contain values
1168 * of primitive types in order for the system to persist these values.
Makoto Onuki4a910962016-07-07 13:57:34 -07001169 *
1170 * @see ShortcutInfo#getIntent()
Makoto Onuki440a1ea2016-07-20 14:21:18 -07001171 * @see #setIntents(Intent[])
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001172 */
1173 @NonNull
1174 public Builder setIntent(@NonNull Intent intent) {
Makoto Onuki440a1ea2016-07-20 14:21:18 -07001175 return setIntents(new Intent[]{intent});
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001176 }
1177
1178 /**
Makoto Onuki0eed4412016-07-21 11:21:59 -07001179 * Sets multiple intents instead of a single intent, in order to launch an activity with
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001180 * other activities in back stack. Use {@link TaskStackBuilder} to build intents. The
1181 * last element in the list represents the only intent that doesn't place an activity on
1182 * the back stack.
Makoto Onuki0eed4412016-07-21 11:21:59 -07001183 * See the {@link ShortcutManager} javadoc for details.
Makoto Onuki347a6bd2016-07-19 11:13:08 -07001184 *
1185 * @see Builder#setIntent(Intent)
1186 * @see ShortcutInfo#getIntents()
1187 * @see Context#startActivities(Intent[])
1188 * @see TaskStackBuilder
1189 */
1190 @NonNull
1191 public Builder setIntents(@NonNull Intent[] intents) {
Makoto Onuki440a1ea2016-07-20 14:21:18 -07001192 Preconditions.checkNotNull(intents, "intents cannot be null");
1193 Preconditions.checkNotNull(intents.length, "intents cannot be empty");
1194 for (Intent intent : intents) {
1195 Preconditions.checkNotNull(intent, "intents cannot contain null");
1196 Preconditions.checkNotNull(intent.getAction(), "intent's action must be set");
1197 }
1198 // Make sure always clone incoming intents.
1199 mIntents = cloneIntents(intents);
1200 return this;
Makoto Onuki347a6bd2016-07-19 11:13:08 -07001201 }
1202
1203 /**
Mehdi Alizadeh14242af2018-12-20 20:11:35 -08001204 * Add a person that is relevant to this shortcut. Alternatively,
1205 * {@link #setPersons(Person[])} can be used to add multiple persons to a shortcut.
1206 *
1207 * <p> This is an optional field, but the addition of person may cause this shortcut to
1208 * appear more prominently in the user interface (e.g. ShareSheet).
1209 *
1210 * <p> A person should usually contain a uri in order to benefit from the ranking boost.
1211 * However, even if no uri is provided, it's beneficial to provide people in the shortcut,
1212 * such that listeners and voice only devices can announce and handle them properly.
1213 *
1214 * @see Person
1215 * @see #setPersons(Person[])
1216 */
1217 @NonNull
1218 public Builder setPerson(@NonNull Person person) {
1219 return setPersons(new Person[]{person});
1220 }
1221
1222 /**
1223 * Sets multiple persons instead of a single person.
1224 *
1225 * @see Person
1226 * @see #setPerson(Person)
1227 */
1228 @NonNull
1229 public Builder setPersons(@NonNull Person[] persons) {
1230 Preconditions.checkNotNull(persons, "persons cannot be null");
1231 Preconditions.checkNotNull(persons.length, "persons cannot be empty");
1232 for (Person person : persons) {
1233 Preconditions.checkNotNull(person, "persons cannot contain null");
1234 }
1235 mPersons = clonePersons(persons);
1236 return this;
1237 }
1238
1239 /**
1240 * Sets if a shortcut would be valid even if it has been unpublished/invisible by the app
1241 * (as a dynamic or pinned shortcut). If it is long lived, it can be cached by various
1242 * system services even after it has been unpublished as a dynamic shortcut.
1243 */
1244 @NonNull
1245 public Builder setLongLived() {
1246 mIsLongLived = true;
1247 return this;
1248 }
1249
1250 /**
Makoto Onuki9e1f5592016-06-08 12:30:23 -07001251 * "Rank" of a shortcut, which is a non-negative value that's used by the launcher app
1252 * to sort shortcuts.
Makoto Onuki4a910962016-07-07 13:57:34 -07001253 *
1254 * See {@link ShortcutInfo#getRank()} for details.
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001255 */
1256 @NonNull
Makoto Onuki20c95f82016-05-11 16:51:01 -07001257 public Builder setRank(int rank) {
Makoto Onuki9e1f5592016-06-08 12:30:23 -07001258 Preconditions.checkArgument((0 <= rank),
1259 "Rank cannot be negative or bigger than MAX_RANK");
Makoto Onuki20c95f82016-05-11 16:51:01 -07001260 mRank = rank;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001261 return this;
1262 }
1263
1264 /**
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001265 * Extras that the app can set for any purpose.
Makoto Onukib5a012f2016-06-21 11:13:53 -07001266 *
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001267 * <p>Apps can store arbitrary shortcut metadata in extras and retrieve the
Makoto Onukife9c9662016-07-25 15:12:23 -07001268 * metadata later using {@link ShortcutInfo#getExtras()}.
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001269 */
1270 @NonNull
1271 public Builder setExtras(@NonNull PersistableBundle extras) {
1272 mExtras = extras;
1273 return this;
1274 }
1275
Hakan Seyalioglu58fc95d2016-12-13 15:23:22 -08001276 /**
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001277 * Creates a {@link ShortcutInfo} instance.
1278 */
1279 @NonNull
1280 public ShortcutInfo build() {
1281 return new ShortcutInfo(this);
1282 }
1283 }
1284
1285 /**
Makoto Onuki4a910962016-07-07 13:57:34 -07001286 * Returns the ID of a shortcut.
1287 *
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001288 * <p>Shortcut IDs are unique within each publisher app and must be stable across
Makoto Onukife9c9662016-07-25 15:12:23 -07001289 * devices so that shortcuts will still be valid when restored on a different device.
1290 * See {@link ShortcutManager} for details.
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001291 */
1292 @NonNull
1293 public String getId() {
1294 return mId;
1295 }
1296
1297 /**
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001298 * Return the package name of the publisher app.
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001299 */
1300 @NonNull
Makoto Onuki22fcc682016-05-17 14:52:19 -07001301 public String getPackage() {
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001302 return mPackageName;
1303 }
1304
1305 /**
Makoto Onuki4a910962016-07-07 13:57:34 -07001306 * Return the target activity.
Makoto Onuki4d36b3a2016-04-27 12:00:17 -07001307 *
Makoto Onukife9c9662016-07-25 15:12:23 -07001308 * <p>This has nothing to do with the activity that this shortcut will launch.
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001309 * Launcher apps should show the launcher icon for the returned activity alongside
Makoto Onukife9c9662016-07-25 15:12:23 -07001310 * this shortcut.
Makoto Onuki4d36b3a2016-04-27 12:00:17 -07001311 *
Makoto Onuki22fcc682016-05-17 14:52:19 -07001312 * @see Builder#setActivity
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001313 */
1314 @Nullable
Makoto Onuki22fcc682016-05-17 14:52:19 -07001315 public ComponentName getActivity() {
1316 return mActivity;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001317 }
1318
Makoto Onukib08790c2016-06-23 14:05:46 -07001319 /** @hide */
1320 public void setActivity(ComponentName activity) {
1321 mActivity = activity;
1322 }
1323
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001324 /**
Makoto Onuki4a910962016-07-07 13:57:34 -07001325 * Returns the shortcut icon.
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001326 *
1327 * @hide
1328 */
1329 @Nullable
Mathew Inwood8c854f82018-09-14 12:35:36 +01001330 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001331 public Icon getIcon() {
1332 return mIcon;
1333 }
1334
Makoto Onukieddbfec2016-05-31 17:04:34 -07001335 /** @hide -- old signature, the internal code still uses it. */
Makoto Onuki55046222016-03-08 10:49:47 -08001336 @Nullable
Makoto Onukib5a012f2016-06-21 11:13:53 -07001337 @Deprecated
Makoto Onuki22fcc682016-05-17 14:52:19 -07001338 public CharSequence getTitle() {
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001339 return mTitle;
1340 }
1341
Makoto Onukieddbfec2016-05-31 17:04:34 -07001342 /** @hide -- old signature, the internal code still uses it. */
Makoto Onukib5a012f2016-06-21 11:13:53 -07001343 @Deprecated
Makoto Onuki20c95f82016-05-11 16:51:01 -07001344 public int getTitleResId() {
1345 return mTitleResId;
1346 }
1347
Makoto Onukieddbfec2016-05-31 17:04:34 -07001348 /** @hide -- old signature, the internal code still uses it. */
1349 @Nullable
Makoto Onukib5a012f2016-06-21 11:13:53 -07001350 @Deprecated
Makoto Onukieddbfec2016-05-31 17:04:34 -07001351 public CharSequence getText() {
1352 return mText;
1353 }
1354
1355 /** @hide -- old signature, the internal code still uses it. */
Makoto Onukib5a012f2016-06-21 11:13:53 -07001356 @Deprecated
Makoto Onukieddbfec2016-05-31 17:04:34 -07001357 public int getTextResId() {
1358 return mTextResId;
1359 }
1360
1361 /**
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001362 * Return the short description of a shortcut.
Makoto Onukieddbfec2016-05-31 17:04:34 -07001363 *
Makoto Onuki4a910962016-07-07 13:57:34 -07001364 * @see Builder#setShortLabel(CharSequence)
Makoto Onukieddbfec2016-05-31 17:04:34 -07001365 */
1366 @Nullable
1367 public CharSequence getShortLabel() {
1368 return mTitle;
1369 }
1370
Makoto Onuki598aca42016-07-06 16:05:03 -07001371 /** @hide */
Makoto Onukieddbfec2016-05-31 17:04:34 -07001372 public int getShortLabelResourceId() {
1373 return mTitleResId;
1374 }
1375
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001376 /**
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001377 * Return the long description of a shortcut.
Makoto Onuki4a910962016-07-07 13:57:34 -07001378 *
1379 * @see Builder#setLongLabel(CharSequence)
Makoto Onukie3ae7ec2016-03-29 15:45:25 -07001380 */
1381 @Nullable
Makoto Onukieddbfec2016-05-31 17:04:34 -07001382 public CharSequence getLongLabel() {
Makoto Onukie3ae7ec2016-03-29 15:45:25 -07001383 return mText;
1384 }
1385
Makoto Onuki598aca42016-07-06 16:05:03 -07001386 /** @hide */
Makoto Onukieddbfec2016-05-31 17:04:34 -07001387 public int getLongLabelResourceId() {
Makoto Onuki20c95f82016-05-11 16:51:01 -07001388 return mTextResId;
1389 }
1390
1391 /**
Makoto Onukife9c9662016-07-25 15:12:23 -07001392 * Return the message that should be shown when the user attempts to start a shortcut
1393 * that is disabled.
Makoto Onuki4a910962016-07-07 13:57:34 -07001394 *
1395 * @see Builder#setDisabledMessage(CharSequence)
Makoto Onuki20c95f82016-05-11 16:51:01 -07001396 */
1397 @Nullable
Makoto Onuki22fcc682016-05-17 14:52:19 -07001398 public CharSequence getDisabledMessage() {
Makoto Onuki20c95f82016-05-11 16:51:01 -07001399 return mDisabledMessage;
1400 }
1401
Makoto Onuki598aca42016-07-06 16:05:03 -07001402 /** @hide */
Makoto Onukieddbfec2016-05-31 17:04:34 -07001403 public int getDisabledMessageResourceId() {
Makoto Onuki20c95f82016-05-11 16:51:01 -07001404 return mDisabledMessageResId;
1405 }
1406
Makoto Onukia4f89b12017-10-05 10:37:55 -07001407 /** @hide */
1408 public void setDisabledReason(@DisabledReason int reason) {
1409 mDisabledReason = reason;
1410 }
1411
1412 /**
1413 * Returns why a shortcut has been disabled.
1414 */
1415 @DisabledReason
1416 public int getDisabledReason() {
1417 return mDisabledReason;
1418 }
1419
Makoto Onukie3ae7ec2016-03-29 15:45:25 -07001420 /**
Makoto Onukife9c9662016-07-25 15:12:23 -07001421 * Return the shortcut's categories.
Makoto Onuki4a910962016-07-07 13:57:34 -07001422 *
1423 * @see Builder#setCategories(Set)
Makoto Onukib6d35232016-04-04 15:57:17 -07001424 */
1425 @Nullable
Makoto Onukibe73a802016-04-15 14:46:35 -07001426 public Set<String> getCategories() {
Makoto Onukib6d35232016-04-04 15:57:17 -07001427 return mCategories;
1428 }
1429
1430 /**
Makoto Onukife9c9662016-07-25 15:12:23 -07001431 * Returns the intent that is executed when the user selects this shortcut.
1432 * If setIntents() was used, then return the last intent in the array.
Makoto Onuki55046222016-03-08 10:49:47 -08001433 *
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001434 * <p>Launcher apps <b>cannot</b> see the intent. If a {@link ShortcutInfo} is
Makoto Onuki4a910962016-07-07 13:57:34 -07001435 * obtained via {@link LauncherApps}, then this method will always return null.
1436 * Launchers can only start a shortcut intent with {@link LauncherApps#startShortcut}.
Makoto Onuki4d36b3a2016-04-27 12:00:17 -07001437 *
Makoto Onuki4a910962016-07-07 13:57:34 -07001438 * @see Builder#setIntent(Intent)
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001439 */
Makoto Onuki55046222016-03-08 10:49:47 -08001440 @Nullable
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001441 public Intent getIntent() {
Makoto Onuki440a1ea2016-07-20 14:21:18 -07001442 if (mIntents == null || mIntents.length == 0) {
Makoto Onuki55046222016-03-08 10:49:47 -08001443 return null;
1444 }
Makoto Onuki440a1ea2016-07-20 14:21:18 -07001445 final int last = mIntents.length - 1;
1446 final Intent intent = new Intent(mIntents[last]);
1447 return setIntentExtras(intent, mIntentPersistableExtrases[last]);
Makoto Onuki55046222016-03-08 10:49:47 -08001448 }
1449
1450 /**
Makoto Onuki347a6bd2016-07-19 11:13:08 -07001451 * Return the intent set with {@link Builder#setIntents(Intent[])}.
1452 *
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001453 * <p>Launcher apps <b>cannot</b> see the intents. If a {@link ShortcutInfo} is
Makoto Onuki347a6bd2016-07-19 11:13:08 -07001454 * obtained via {@link LauncherApps}, then this method will always return null.
1455 * Launchers can only start a shortcut intent with {@link LauncherApps#startShortcut}.
1456 *
1457 * @see Builder#setIntents(Intent[])
1458 */
1459 @Nullable
Makoto Onuki440a1ea2016-07-20 14:21:18 -07001460 public Intent[] getIntents() {
1461 final Intent[] ret = new Intent[mIntents.length];
1462
1463 for (int i = 0; i < ret.length; i++) {
1464 ret[i] = new Intent(mIntents[i]);
1465 setIntentExtras(ret[i], mIntentPersistableExtrases[i]);
1466 }
1467
1468 return ret;
Makoto Onuki347a6bd2016-07-19 11:13:08 -07001469 }
1470
1471 /**
Makoto Onuki440a1ea2016-07-20 14:21:18 -07001472 * Return "raw" intents, which is the original intents without the extras.
Makoto Onuki55046222016-03-08 10:49:47 -08001473 * @hide
1474 */
1475 @Nullable
Makoto Onuki440a1ea2016-07-20 14:21:18 -07001476 public Intent[] getIntentsNoExtras() {
1477 return mIntents;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001478 }
1479
Makoto Onuki55046222016-03-08 10:49:47 -08001480 /**
Mehdi Alizadeh14242af2018-12-20 20:11:35 -08001481 * Return the Persons set with {@link Builder#setPersons(Person[])}.
1482 *
1483 * @hide
1484 */
1485 @Nullable
Mehdi Alizadeh88873652019-02-04 14:16:46 -08001486 @SystemApi
Mehdi Alizadeh14242af2018-12-20 20:11:35 -08001487 public Person[] getPersons() {
1488 return clonePersons(mPersons);
1489 }
1490
1491 /**
Makoto Onuki440a1ea2016-07-20 14:21:18 -07001492 * The extras in the intents. We convert extras into {@link PersistableBundle} so we can
Makoto Onuki55046222016-03-08 10:49:47 -08001493 * persist them.
1494 * @hide
1495 */
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001496 @Nullable
Makoto Onuki440a1ea2016-07-20 14:21:18 -07001497 public PersistableBundle[] getIntentPersistableExtrases() {
1498 return mIntentPersistableExtrases;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001499 }
1500
Hakan Seyalioglu58fc95d2016-12-13 15:23:22 -08001501 /**
Makoto Onuki9e1f5592016-06-08 12:30:23 -07001502 * "Rank" of a shortcut, which is a non-negative, sequential value that's unique for each
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001503 * {@link #getActivity} for each of the two types of shortcuts (static and dynamic).
Makoto Onuki9e1f5592016-06-08 12:30:23 -07001504 *
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001505 * <p>Because static shortcuts and dynamic shortcuts have overlapping ranks,
1506 * when a launcher app shows shortcuts for an activity, it should first show
1507 * the static shortcuts, followed by the dynamic shortcuts. Within each of those categories,
Makoto Onuki9e1f5592016-06-08 12:30:23 -07001508 * shortcuts should be sorted by rank in ascending order.
1509 *
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001510 * <p><em>Floating shortcuts</em>, or shortcuts that are neither static nor dynamic, will all
1511 * have rank 0, because they aren't sorted.
Makoto Onuki4a910962016-07-07 13:57:34 -07001512 *
1513 * See the {@link ShortcutManager}'s class javadoc for details.
1514 *
1515 * @see Builder#setRank(int)
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001516 */
Makoto Onuki20c95f82016-05-11 16:51:01 -07001517 public int getRank() {
1518 return mRank;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001519 }
1520
Makoto Onuki9e1f5592016-06-08 12:30:23 -07001521 /** @hide */
1522 public boolean hasRank() {
1523 return mRank != RANK_NOT_SET;
1524 }
1525
1526 /** @hide */
1527 public void setRank(int rank) {
1528 mRank = rank;
1529 }
1530
1531 /** @hide */
1532 public void clearImplicitRankAndRankChangedFlag() {
1533 mImplicitRank = 0;
1534 }
1535
1536 /** @hide */
1537 public void setImplicitRank(int rank) {
1538 // Make sure to keep RANK_CHANGED_BIT.
1539 mImplicitRank = (mImplicitRank & RANK_CHANGED_BIT) | (rank & IMPLICIT_RANK_MASK);
1540 }
1541
1542 /** @hide */
1543 public int getImplicitRank() {
1544 return mImplicitRank & IMPLICIT_RANK_MASK;
1545 }
1546
1547 /** @hide */
1548 public void setRankChanged() {
1549 mImplicitRank |= RANK_CHANGED_BIT;
1550 }
1551
1552 /** @hide */
1553 public boolean isRankChanged() {
1554 return (mImplicitRank & RANK_CHANGED_BIT) != 0;
1555 }
1556
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001557 /**
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001558 * Extras that the app can set for any purpose.
Makoto Onuki4a910962016-07-07 13:57:34 -07001559 *
1560 * @see Builder#setExtras(PersistableBundle)
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001561 */
1562 @Nullable
1563 public PersistableBundle getExtras() {
1564 return mExtras;
1565 }
1566
Makoto Onukiabe84422016-04-07 09:41:19 -07001567 /** @hide */
1568 public int getUserId() {
1569 return mUserId;
1570 }
1571
1572 /**
Makoto Onukife9c9662016-07-25 15:12:23 -07001573 * {@link UserHandle} on which the publisher created this shortcut.
Makoto Onukiabe84422016-04-07 09:41:19 -07001574 */
1575 public UserHandle getUserHandle() {
1576 return UserHandle.of(mUserId);
1577 }
1578
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001579 /**
1580 * Last time when any of the fields was updated.
1581 */
1582 public long getLastChangedTimestamp() {
1583 return mLastChangedTimestamp;
1584 }
1585
1586 /** @hide */
1587 @ShortcutFlags
1588 public int getFlags() {
1589 return mFlags;
1590 }
1591
1592 /** @hide*/
Makoto Onukide667372016-03-15 14:29:20 -07001593 public void replaceFlags(@ShortcutFlags int flags) {
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001594 mFlags = flags;
1595 }
1596
1597 /** @hide*/
1598 public void addFlags(@ShortcutFlags int flags) {
1599 mFlags |= flags;
1600 }
1601
1602 /** @hide*/
1603 public void clearFlags(@ShortcutFlags int flags) {
1604 mFlags &= ~flags;
1605 }
1606
1607 /** @hide*/
1608 public boolean hasFlags(@ShortcutFlags int flags) {
1609 return (mFlags & flags) == flags;
1610 }
1611
Makoto Onukibf563b62017-05-04 10:25:30 -07001612 /** @hide */
1613 public boolean isReturnedByServer() {
1614 return hasFlags(FLAG_RETURNED_BY_SERVICE);
1615 }
1616
1617 /** @hide */
1618 public void setReturnedByServer() {
1619 addFlags(FLAG_RETURNED_BY_SERVICE);
1620 }
1621
Mehdi Alizadeh14242af2018-12-20 20:11:35 -08001622 /** @hide */
1623 public boolean isLongLived() {
1624 return hasFlags(FLAG_LONG_LIVED);
1625 }
1626
1627 /** @hide */
1628 public void setLongLived() {
1629 addFlags(FLAG_LONG_LIVED);
1630 }
1631
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001632 /** Return whether a shortcut is dynamic. */
1633 public boolean isDynamic() {
1634 return hasFlags(FLAG_DYNAMIC);
1635 }
1636
1637 /** Return whether a shortcut is pinned. */
1638 public boolean isPinned() {
1639 return hasFlags(FLAG_PINNED);
1640 }
1641
1642 /**
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001643 * Return whether a shortcut is static; that is, whether a shortcut is
1644 * published from AndroidManifest.xml. If {@code true}, the shortcut is
1645 * also {@link #isImmutable()}.
Makoto Onuki22fcc682016-05-17 14:52:19 -07001646 *
1647 * <p>When an app is upgraded and a shortcut is no longer published from AndroidManifest.xml,
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001648 * this will be set to {@code false}. If the shortcut is not pinned, then it'll disappear.
1649 * However, if it's pinned, it will still be visible, {@link #isEnabled()} will be
Makoto Onuki22fcc682016-05-17 14:52:19 -07001650 * {@code false} and {@link #isImmutable()} will be {@code true}.
Makoto Onuki20c95f82016-05-11 16:51:01 -07001651 */
Makoto Onukib5a012f2016-06-21 11:13:53 -07001652 public boolean isDeclaredInManifest() {
Makoto Onuki22fcc682016-05-17 14:52:19 -07001653 return hasFlags(FLAG_MANIFEST);
Makoto Onuki20c95f82016-05-11 16:51:01 -07001654 }
1655
Makoto Onukib5a012f2016-06-21 11:13:53 -07001656 /** @hide kept for unit tests */
1657 @Deprecated
1658 public boolean isManifestShortcut() {
1659 return isDeclaredInManifest();
1660 }
1661
Makoto Onuki22fcc682016-05-17 14:52:19 -07001662 /**
Makoto Onuki9fd90192017-01-06 18:31:03 +00001663 * @return true if pinned but neither static nor dynamic.
Makoto Onuki22fcc682016-05-17 14:52:19 -07001664 * @hide
1665 */
1666 public boolean isFloating() {
1667 return isPinned() && !(isDynamic() || isManifestShortcut());
1668 }
1669
1670 /** @hide */
1671 public boolean isOriginallyFromManifest() {
1672 return hasFlags(FLAG_IMMUTABLE);
1673 }
1674
Makoto Onukia4f89b12017-10-05 10:37:55 -07001675 /** @hide */
1676 public boolean isDynamicVisible() {
1677 return isDynamic() && isVisibleToPublisher();
1678 }
1679
1680 /** @hide */
1681 public boolean isPinnedVisible() {
1682 return isPinned() && isVisibleToPublisher();
1683 }
1684
1685 /** @hide */
1686 public boolean isManifestVisible() {
1687 return isDeclaredInManifest() && isVisibleToPublisher();
1688 }
1689
Makoto Onuki22fcc682016-05-17 14:52:19 -07001690 /**
1691 * Return if a shortcut is immutable, in which case it cannot be modified with any of
1692 * {@link ShortcutManager} APIs.
1693 *
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001694 * <p>All static shortcuts are immutable. When a static shortcut is pinned and is then
1695 * disabled because it doesn't appear in AndroidManifest.xml for a newer version of the
1696 * app, {@link #isDeclaredInManifest()} returns {@code false}, but the shortcut
1697 * is still immutable.
Makoto Onuki22fcc682016-05-17 14:52:19 -07001698 *
1699 * <p>All shortcuts originally published via the {@link ShortcutManager} APIs
1700 * are all mutable.
1701 */
1702 public boolean isImmutable() {
1703 return hasFlags(FLAG_IMMUTABLE);
1704 }
1705
1706 /**
1707 * Returns {@code false} if a shortcut is disabled with
1708 * {@link ShortcutManager#disableShortcuts}.
1709 */
1710 public boolean isEnabled() {
Makoto Onuki20c95f82016-05-11 16:51:01 -07001711 return !hasFlags(FLAG_DISABLED);
1712 }
1713
Makoto Onuki22fcc682016-05-17 14:52:19 -07001714 /** @hide */
1715 public boolean isAlive() {
1716 return hasFlags(FLAG_PINNED) || hasFlags(FLAG_DYNAMIC) || hasFlags(FLAG_MANIFEST);
1717 }
1718
1719 /** @hide */
1720 public boolean usesQuota() {
1721 return hasFlags(FLAG_DYNAMIC) || hasFlags(FLAG_MANIFEST);
1722 }
1723
Makoto Onuki20c95f82016-05-11 16:51:01 -07001724 /**
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001725 * Return whether a shortcut's icon is a resource in the owning package.
1726 *
Makoto Onukib5a012f2016-06-21 11:13:53 -07001727 * @hide internal/unit tests only
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001728 */
1729 public boolean hasIconResource() {
1730 return hasFlags(FLAG_HAS_ICON_RES);
1731 }
1732
Makoto Onuki20c95f82016-05-11 16:51:01 -07001733 /** @hide */
1734 public boolean hasStringResources() {
1735 return (mTitleResId != 0) || (mTextResId != 0) || (mDisabledMessageResId != 0);
1736 }
1737
1738 /** @hide */
1739 public boolean hasAnyResources() {
1740 return hasIconResource() || hasStringResources();
1741 }
1742
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001743 /**
1744 * Return whether a shortcut's icon is stored as a file.
1745 *
Makoto Onukib5a012f2016-06-21 11:13:53 -07001746 * @hide internal/unit tests only
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001747 */
1748 public boolean hasIconFile() {
1749 return hasFlags(FLAG_HAS_ICON_FILE);
1750 }
1751
Makoto Onuki55046222016-03-08 10:49:47 -08001752 /**
Hyunyoung Songe4179e22017-03-01 12:51:26 -08001753 * Return whether a shortcut's icon is adaptive bitmap following design guideline
Makoto Onukibf563b62017-05-04 10:25:30 -07001754 * defined in {@link android.graphics.drawable.AdaptiveIconDrawable}.
Hyunyoung Songf281e7a2017-02-13 10:57:42 -08001755 *
1756 * @hide internal/unit tests only
1757 */
Hyunyoung Songe4179e22017-03-01 12:51:26 -08001758 public boolean hasAdaptiveBitmap() {
1759 return hasFlags(FLAG_ADAPTIVE_BITMAP);
Hyunyoung Songf281e7a2017-02-13 10:57:42 -08001760 }
1761
Makoto Onuki475c3652017-05-08 14:29:03 -07001762 /** @hide */
1763 public boolean isIconPendingSave() {
1764 return hasFlags(FLAG_ICON_FILE_PENDING_SAVE);
1765 }
1766
1767 /** @hide */
1768 public void setIconPendingSave() {
1769 addFlags(FLAG_ICON_FILE_PENDING_SAVE);
1770 }
1771
1772 /** @hide */
1773 public void clearIconPendingSave() {
1774 clearFlags(FLAG_ICON_FILE_PENDING_SAVE);
1775 }
1776
Hyunyoung Songf281e7a2017-02-13 10:57:42 -08001777 /**
Makoto Onukia4f89b12017-10-05 10:37:55 -07001778 * When the system wasn't able to restore a shortcut, it'll still be registered to the system
1779 * but disabled, and such shortcuts will not be visible to the publisher. They're still visible
1780 * to launchers though.
1781 *
1782 * @hide
1783 */
1784 @TestApi
1785 public boolean isVisibleToPublisher() {
1786 return !isDisabledForRestoreIssue(mDisabledReason);
1787 }
1788
1789 /**
Makoto Onuki55046222016-03-08 10:49:47 -08001790 * Return whether a shortcut only contains "key" information only or not. If true, only the
1791 * following fields are available.
1792 * <ul>
1793 * <li>{@link #getId()}
Makoto Onuki22fcc682016-05-17 14:52:19 -07001794 * <li>{@link #getPackage()}
Makoto Onuki4d6b87f2016-06-17 13:47:40 -07001795 * <li>{@link #getActivity()}
Makoto Onuki55046222016-03-08 10:49:47 -08001796 * <li>{@link #getLastChangedTimestamp()}
1797 * <li>{@link #isDynamic()}
1798 * <li>{@link #isPinned()}
Makoto Onukib5a012f2016-06-21 11:13:53 -07001799 * <li>{@link #isDeclaredInManifest()}
1800 * <li>{@link #isImmutable()}
1801 * <li>{@link #isEnabled()}
1802 * <li>{@link #getUserHandle()}
Makoto Onuki55046222016-03-08 10:49:47 -08001803 * </ul>
Makoto Onuki4a910962016-07-07 13:57:34 -07001804 *
Makoto Onukife9c9662016-07-25 15:12:23 -07001805 * <p>For performance reasons, shortcuts passed to
1806 * {@link LauncherApps.Callback#onShortcutsChanged(String, List, UserHandle)} as well as those
1807 * returned from {@link LauncherApps#getShortcuts(ShortcutQuery, UserHandle)}
1808 * while using the {@link ShortcutQuery#FLAG_GET_KEY_FIELDS_ONLY} option contain only key
1809 * information.
Makoto Onuki55046222016-03-08 10:49:47 -08001810 */
1811 public boolean hasKeyFieldsOnly() {
1812 return hasFlags(FLAG_KEY_FIELDS_ONLY);
1813 }
1814
Makoto Onukib5a012f2016-06-21 11:13:53 -07001815 /** @hide */
Makoto Onuki20c95f82016-05-11 16:51:01 -07001816 public boolean hasStringResourcesResolved() {
1817 return hasFlags(FLAG_STRINGS_RESOLVED);
1818 }
1819
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001820 /** @hide */
1821 public void updateTimestamp() {
1822 mLastChangedTimestamp = System.currentTimeMillis();
1823 }
1824
1825 /** @hide */
1826 // VisibleForTesting
1827 public void setTimestamp(long value) {
1828 mLastChangedTimestamp = value;
1829 }
1830
1831 /** @hide */
Makoto Onuki55046222016-03-08 10:49:47 -08001832 public void clearIcon() {
1833 mIcon = null;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001834 }
1835
1836 /** @hide */
Makoto Onuki55046222016-03-08 10:49:47 -08001837 public void setIconResourceId(int iconResourceId) {
Makoto Onuki157b1622016-06-02 16:13:10 -07001838 if (mIconResId != iconResourceId) {
1839 mIconResName = null;
1840 }
1841 mIconResId = iconResourceId;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001842 }
1843
Makoto Onukib6d35232016-04-04 15:57:17 -07001844 /**
1845 * Get the resource ID for the icon, valid only when {@link #hasIconResource()} } is true.
Makoto Onukib5a012f2016-06-21 11:13:53 -07001846 * @hide internal / tests only.
Makoto Onukib6d35232016-04-04 15:57:17 -07001847 */
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001848 public int getIconResourceId() {
Makoto Onuki157b1622016-06-02 16:13:10 -07001849 return mIconResId;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001850 }
1851
Makoto Onuki475c3652017-05-08 14:29:03 -07001852 /**
1853 * Bitmap path. Note this will be null even if {@link #hasIconFile()} is set when the save
1854 * is pending. Use {@link #isIconPendingSave()} to check it.
1855 *
1856 * @hide
1857 */
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001858 public String getBitmapPath() {
1859 return mBitmapPath;
1860 }
1861
1862 /** @hide */
1863 public void setBitmapPath(String bitmapPath) {
1864 mBitmapPath = bitmapPath;
1865 }
1866
Makoto Onuki22fcc682016-05-17 14:52:19 -07001867 /** @hide */
1868 public void setDisabledMessageResId(int disabledMessageResId) {
Makoto Onuki157b1622016-06-02 16:13:10 -07001869 if (mDisabledMessageResId != disabledMessageResId) {
1870 mDisabledMessageResName = null;
1871 }
Makoto Onuki22fcc682016-05-17 14:52:19 -07001872 mDisabledMessageResId = disabledMessageResId;
1873 mDisabledMessage = null;
1874 }
1875
1876 /** @hide */
1877 public void setDisabledMessage(String disabledMessage) {
1878 mDisabledMessage = disabledMessage;
1879 mDisabledMessageResId = 0;
Makoto Onuki157b1622016-06-02 16:13:10 -07001880 mDisabledMessageResName = null;
1881 }
1882
1883 /** @hide */
1884 public String getTitleResName() {
1885 return mTitleResName;
1886 }
1887
1888 /** @hide */
1889 public void setTitleResName(String titleResName) {
1890 mTitleResName = titleResName;
1891 }
1892
1893 /** @hide */
1894 public String getTextResName() {
1895 return mTextResName;
1896 }
1897
1898 /** @hide */
1899 public void setTextResName(String textResName) {
1900 mTextResName = textResName;
1901 }
1902
1903 /** @hide */
1904 public String getDisabledMessageResName() {
1905 return mDisabledMessageResName;
1906 }
1907
1908 /** @hide */
1909 public void setDisabledMessageResName(String disabledMessageResName) {
1910 mDisabledMessageResName = disabledMessageResName;
1911 }
1912
1913 /** @hide */
1914 public String getIconResName() {
1915 return mIconResName;
1916 }
1917
1918 /** @hide */
1919 public void setIconResName(String iconResName) {
1920 mIconResName = iconResName;
Makoto Onuki22fcc682016-05-17 14:52:19 -07001921 }
1922
Makoto Onukidf6da042016-06-16 09:51:40 -07001923 /**
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001924 * Replaces the intent.
Makoto Onukidf6da042016-06-16 09:51:40 -07001925 *
1926 * @throws IllegalArgumentException when extra is not compatible with {@link PersistableBundle}.
1927 *
1928 * @hide
1929 */
Makoto Onuki440a1ea2016-07-20 14:21:18 -07001930 public void setIntents(Intent[] intents) throws IllegalArgumentException {
1931 Preconditions.checkNotNull(intents);
1932 Preconditions.checkArgument(intents.length > 0);
Makoto Onukidf6da042016-06-16 09:51:40 -07001933
Makoto Onuki440a1ea2016-07-20 14:21:18 -07001934 mIntents = cloneIntents(intents);
1935 fixUpIntentExtras();
1936 }
Makoto Onukidf6da042016-06-16 09:51:40 -07001937
Makoto Onuki440a1ea2016-07-20 14:21:18 -07001938 /** @hide */
1939 public static Intent setIntentExtras(Intent intent, PersistableBundle extras) {
1940 if (extras == null) {
Makoto Onukidf6da042016-06-16 09:51:40 -07001941 intent.replaceExtras((Bundle) null);
Makoto Onukidf6da042016-06-16 09:51:40 -07001942 } else {
Makoto Onuki440a1ea2016-07-20 14:21:18 -07001943 intent.replaceExtras(new Bundle(extras));
Makoto Onukidf6da042016-06-16 09:51:40 -07001944 }
Makoto Onuki440a1ea2016-07-20 14:21:18 -07001945 return intent;
Makoto Onukidf6da042016-06-16 09:51:40 -07001946 }
1947
1948 /**
1949 * Replaces the categories.
1950 *
1951 * @hide
1952 */
1953 public void setCategories(Set<String> categories) {
1954 mCategories = cloneCategories(categories);
1955 }
1956
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001957 private ShortcutInfo(Parcel source) {
1958 final ClassLoader cl = getClass().getClassLoader();
1959
Makoto Onukiabe84422016-04-07 09:41:19 -07001960 mUserId = source.readInt();
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001961 mId = source.readString();
1962 mPackageName = source.readString();
Makoto Onuki22fcc682016-05-17 14:52:19 -07001963 mActivity = source.readParcelable(cl);
Makoto Onuki4d6b87f2016-06-17 13:47:40 -07001964 mFlags = source.readInt();
1965 mIconResId = source.readInt();
1966 mLastChangedTimestamp = source.readLong();
Makoto Onukia4f89b12017-10-05 10:37:55 -07001967 mDisabledReason = source.readInt();
Makoto Onuki4d6b87f2016-06-17 13:47:40 -07001968
1969 if (source.readInt() == 0) {
1970 return; // key information only.
1971 }
1972
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001973 mIcon = source.readParcelable(cl);
Makoto Onuki22fcc682016-05-17 14:52:19 -07001974 mTitle = source.readCharSequence();
Makoto Onuki20c95f82016-05-11 16:51:01 -07001975 mTitleResId = source.readInt();
Makoto Onuki22fcc682016-05-17 14:52:19 -07001976 mText = source.readCharSequence();
Makoto Onuki20c95f82016-05-11 16:51:01 -07001977 mTextResId = source.readInt();
Makoto Onuki22fcc682016-05-17 14:52:19 -07001978 mDisabledMessage = source.readCharSequence();
Makoto Onuki20c95f82016-05-11 16:51:01 -07001979 mDisabledMessageResId = source.readInt();
Makoto Onuki440a1ea2016-07-20 14:21:18 -07001980 mIntents = source.readParcelableArray(cl, Intent.class);
1981 mIntentPersistableExtrases = source.readParcelableArray(cl, PersistableBundle.class);
Makoto Onuki20c95f82016-05-11 16:51:01 -07001982 mRank = source.readInt();
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001983 mExtras = source.readParcelable(cl);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001984 mBitmapPath = source.readString();
Makoto Onukibe73a802016-04-15 14:46:35 -07001985
Makoto Onuki157b1622016-06-02 16:13:10 -07001986 mIconResName = source.readString();
1987 mTitleResName = source.readString();
1988 mTextResName = source.readString();
1989 mDisabledMessageResName = source.readString();
1990
Makoto Onukibe73a802016-04-15 14:46:35 -07001991 int N = source.readInt();
1992 if (N == 0) {
1993 mCategories = null;
1994 } else {
1995 mCategories = new ArraySet<>(N);
1996 for (int i = 0; i < N; i++) {
1997 mCategories.add(source.readString().intern());
1998 }
1999 }
Mehdi Alizadeh14242af2018-12-20 20:11:35 -08002000
2001 mPersons = source.readParcelableArray(cl, Person.class);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002002 }
2003
2004 @Override
2005 public void writeToParcel(Parcel dest, int flags) {
Makoto Onukiabe84422016-04-07 09:41:19 -07002006 dest.writeInt(mUserId);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002007 dest.writeString(mId);
2008 dest.writeString(mPackageName);
Makoto Onuki22fcc682016-05-17 14:52:19 -07002009 dest.writeParcelable(mActivity, flags);
Makoto Onuki4d6b87f2016-06-17 13:47:40 -07002010 dest.writeInt(mFlags);
2011 dest.writeInt(mIconResId);
2012 dest.writeLong(mLastChangedTimestamp);
Makoto Onukia4f89b12017-10-05 10:37:55 -07002013 dest.writeInt(mDisabledReason);
Makoto Onuki4d6b87f2016-06-17 13:47:40 -07002014
2015 if (hasKeyFieldsOnly()) {
2016 dest.writeInt(0);
2017 return;
2018 }
2019 dest.writeInt(1);
2020
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002021 dest.writeParcelable(mIcon, flags);
Makoto Onuki22fcc682016-05-17 14:52:19 -07002022 dest.writeCharSequence(mTitle);
Makoto Onuki20c95f82016-05-11 16:51:01 -07002023 dest.writeInt(mTitleResId);
Makoto Onuki22fcc682016-05-17 14:52:19 -07002024 dest.writeCharSequence(mText);
Makoto Onuki20c95f82016-05-11 16:51:01 -07002025 dest.writeInt(mTextResId);
Makoto Onuki22fcc682016-05-17 14:52:19 -07002026 dest.writeCharSequence(mDisabledMessage);
Makoto Onuki20c95f82016-05-11 16:51:01 -07002027 dest.writeInt(mDisabledMessageResId);
Makoto Onukibe73a802016-04-15 14:46:35 -07002028
Makoto Onuki440a1ea2016-07-20 14:21:18 -07002029 dest.writeParcelableArray(mIntents, flags);
2030 dest.writeParcelableArray(mIntentPersistableExtrases, flags);
Makoto Onuki20c95f82016-05-11 16:51:01 -07002031 dest.writeInt(mRank);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002032 dest.writeParcelable(mExtras, flags);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002033 dest.writeString(mBitmapPath);
Makoto Onukibe73a802016-04-15 14:46:35 -07002034
Makoto Onuki157b1622016-06-02 16:13:10 -07002035 dest.writeString(mIconResName);
2036 dest.writeString(mTitleResName);
2037 dest.writeString(mTextResName);
2038 dest.writeString(mDisabledMessageResName);
2039
Makoto Onukibe73a802016-04-15 14:46:35 -07002040 if (mCategories != null) {
2041 final int N = mCategories.size();
2042 dest.writeInt(N);
2043 for (int i = 0; i < N; i++) {
2044 dest.writeString(mCategories.valueAt(i));
2045 }
2046 } else {
2047 dest.writeInt(0);
2048 }
Mehdi Alizadeh14242af2018-12-20 20:11:35 -08002049
2050 dest.writeParcelableArray(mPersons, flags);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002051 }
2052
2053 public static final Creator<ShortcutInfo> CREATOR =
2054 new Creator<ShortcutInfo>() {
2055 public ShortcutInfo createFromParcel(Parcel source) {
2056 return new ShortcutInfo(source);
2057 }
2058 public ShortcutInfo[] newArray(int size) {
2059 return new ShortcutInfo[size];
2060 }
2061 };
2062
2063 @Override
2064 public int describeContents() {
2065 return 0;
2066 }
2067
Makoto Onuki6208c672017-10-02 16:20:35 -07002068
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002069 /**
2070 * Return a string representation, intended for logging. Some fields will be retracted.
2071 */
2072 @Override
2073 public String toString() {
Makoto Onuki6208c672017-10-02 16:20:35 -07002074 return toStringInner(/* secure =*/ true, /* includeInternalData =*/ false,
2075 /*indent=*/ null);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002076 }
2077
2078 /** @hide */
2079 public String toInsecureString() {
Makoto Onuki6208c672017-10-02 16:20:35 -07002080 return toStringInner(/* secure =*/ false, /* includeInternalData =*/ true,
2081 /*indent=*/ null);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002082 }
2083
Makoto Onuki6208c672017-10-02 16:20:35 -07002084 /** @hide */
2085 public String toDumpString(String indent) {
2086 return toStringInner(/* secure =*/ false, /* includeInternalData =*/ true, indent);
2087 }
2088
2089 private void addIndentOrComma(StringBuilder sb, String indent) {
2090 if (indent != null) {
2091 sb.append("\n ");
2092 sb.append(indent);
2093 } else {
2094 sb.append(", ");
2095 }
2096 }
2097
2098 private String toStringInner(boolean secure, boolean includeInternalData, String indent) {
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002099 final StringBuilder sb = new StringBuilder();
Makoto Onuki6208c672017-10-02 16:20:35 -07002100
2101 if (indent != null) {
2102 sb.append(indent);
2103 }
2104
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002105 sb.append("ShortcutInfo {");
2106
2107 sb.append("id=");
2108 sb.append(secure ? "***" : mId);
2109
Makoto Onuki22fcc682016-05-17 14:52:19 -07002110 sb.append(", flags=0x");
2111 sb.append(Integer.toHexString(mFlags));
2112 sb.append(" [");
Makoto Onukia4f89b12017-10-05 10:37:55 -07002113 if ((mFlags & FLAG_SHADOW) != 0) {
2114 // Note the shadow flag isn't actually used anywhere and it's just for dumpsys, so
2115 // we don't have an isXxx for this.
2116 sb.append("Sdw");
2117 }
Makoto Onuki22fcc682016-05-17 14:52:19 -07002118 if (!isEnabled()) {
Makoto Onuki6208c672017-10-02 16:20:35 -07002119 sb.append("Dis");
Makoto Onuki22fcc682016-05-17 14:52:19 -07002120 }
2121 if (isImmutable()) {
2122 sb.append("Im");
2123 }
2124 if (isManifestShortcut()) {
Makoto Onuki6208c672017-10-02 16:20:35 -07002125 sb.append("Man");
Makoto Onuki22fcc682016-05-17 14:52:19 -07002126 }
2127 if (isDynamic()) {
Makoto Onuki6208c672017-10-02 16:20:35 -07002128 sb.append("Dyn");
Makoto Onuki22fcc682016-05-17 14:52:19 -07002129 }
2130 if (isPinned()) {
Makoto Onuki6208c672017-10-02 16:20:35 -07002131 sb.append("Pin");
Makoto Onuki22fcc682016-05-17 14:52:19 -07002132 }
2133 if (hasIconFile()) {
Makoto Onuki6208c672017-10-02 16:20:35 -07002134 sb.append("Ic-f");
Makoto Onuki22fcc682016-05-17 14:52:19 -07002135 }
Makoto Onuki475c3652017-05-08 14:29:03 -07002136 if (isIconPendingSave()) {
Makoto Onuki6208c672017-10-02 16:20:35 -07002137 sb.append("Pens");
Makoto Onuki475c3652017-05-08 14:29:03 -07002138 }
Makoto Onuki22fcc682016-05-17 14:52:19 -07002139 if (hasIconResource()) {
Makoto Onuki6208c672017-10-02 16:20:35 -07002140 sb.append("Ic-r");
Makoto Onuki22fcc682016-05-17 14:52:19 -07002141 }
2142 if (hasKeyFieldsOnly()) {
Makoto Onuki6208c672017-10-02 16:20:35 -07002143 sb.append("Key");
Makoto Onuki22fcc682016-05-17 14:52:19 -07002144 }
2145 if (hasStringResourcesResolved()) {
Makoto Onuki6208c672017-10-02 16:20:35 -07002146 sb.append("Str");
Makoto Onuki22fcc682016-05-17 14:52:19 -07002147 }
Makoto Onukibf563b62017-05-04 10:25:30 -07002148 if (isReturnedByServer()) {
Makoto Onuki6208c672017-10-02 16:20:35 -07002149 sb.append("Rets");
Makoto Onukibf563b62017-05-04 10:25:30 -07002150 }
Mehdi Alizadeh14242af2018-12-20 20:11:35 -08002151 if (isLongLived()) {
2152 sb.append("Liv");
2153 }
Makoto Onuki22fcc682016-05-17 14:52:19 -07002154 sb.append("]");
2155
Makoto Onuki6208c672017-10-02 16:20:35 -07002156 addIndentOrComma(sb, indent);
2157
2158 sb.append("packageName=");
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002159 sb.append(mPackageName);
2160
Makoto Onukia4f89b12017-10-05 10:37:55 -07002161 addIndentOrComma(sb, indent);
2162
2163 sb.append("activity=");
Makoto Onuki22fcc682016-05-17 14:52:19 -07002164 sb.append(mActivity);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002165
Makoto Onuki6208c672017-10-02 16:20:35 -07002166 addIndentOrComma(sb, indent);
2167
2168 sb.append("shortLabel=");
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002169 sb.append(secure ? "***" : mTitle);
Makoto Onukieddbfec2016-05-31 17:04:34 -07002170 sb.append(", resId=");
Makoto Onuki20c95f82016-05-11 16:51:01 -07002171 sb.append(mTitleResId);
Makoto Onuki157b1622016-06-02 16:13:10 -07002172 sb.append("[");
2173 sb.append(mTitleResName);
2174 sb.append("]");
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002175
Makoto Onuki6208c672017-10-02 16:20:35 -07002176 addIndentOrComma(sb, indent);
2177
2178 sb.append("longLabel=");
Makoto Onukie3ae7ec2016-03-29 15:45:25 -07002179 sb.append(secure ? "***" : mText);
Makoto Onukieddbfec2016-05-31 17:04:34 -07002180 sb.append(", resId=");
Makoto Onuki20c95f82016-05-11 16:51:01 -07002181 sb.append(mTextResId);
Makoto Onuki157b1622016-06-02 16:13:10 -07002182 sb.append("[");
2183 sb.append(mTextResName);
2184 sb.append("]");
Makoto Onuki20c95f82016-05-11 16:51:01 -07002185
Makoto Onuki6208c672017-10-02 16:20:35 -07002186 addIndentOrComma(sb, indent);
2187
2188 sb.append("disabledMessage=");
Makoto Onuki20c95f82016-05-11 16:51:01 -07002189 sb.append(secure ? "***" : mDisabledMessage);
Makoto Onukieddbfec2016-05-31 17:04:34 -07002190 sb.append(", resId=");
Makoto Onuki20c95f82016-05-11 16:51:01 -07002191 sb.append(mDisabledMessageResId);
Makoto Onuki157b1622016-06-02 16:13:10 -07002192 sb.append("[");
2193 sb.append(mDisabledMessageResName);
2194 sb.append("]");
Makoto Onukie3ae7ec2016-03-29 15:45:25 -07002195
Makoto Onuki6208c672017-10-02 16:20:35 -07002196 addIndentOrComma(sb, indent);
2197
Makoto Onukia4f89b12017-10-05 10:37:55 -07002198 sb.append("disabledReason=");
Makoto Onukib1588c02017-10-12 15:11:45 -07002199 sb.append(getDisabledReasonDebugString(mDisabledReason));
Makoto Onukia4f89b12017-10-05 10:37:55 -07002200
2201 addIndentOrComma(sb, indent);
2202
Makoto Onuki6208c672017-10-02 16:20:35 -07002203 sb.append("categories=");
Makoto Onukib6d35232016-04-04 15:57:17 -07002204 sb.append(mCategories);
2205
Makoto Onuki6208c672017-10-02 16:20:35 -07002206 addIndentOrComma(sb, indent);
2207
Mehdi Alizadeh14242af2018-12-20 20:11:35 -08002208 sb.append("persons=");
2209 sb.append(mPersons);
2210
2211 addIndentOrComma(sb, indent);
2212
Makoto Onuki6208c672017-10-02 16:20:35 -07002213 sb.append("icon=");
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002214 sb.append(mIcon);
2215
Makoto Onuki6208c672017-10-02 16:20:35 -07002216 addIndentOrComma(sb, indent);
2217
2218 sb.append("rank=");
Makoto Onuki20c95f82016-05-11 16:51:01 -07002219 sb.append(mRank);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002220
2221 sb.append(", timestamp=");
2222 sb.append(mLastChangedTimestamp);
2223
Makoto Onuki6208c672017-10-02 16:20:35 -07002224 addIndentOrComma(sb, indent);
2225
2226 sb.append("intents=");
Makoto Onuki440a1ea2016-07-20 14:21:18 -07002227 if (mIntents == null) {
2228 sb.append("null");
2229 } else {
2230 if (secure) {
2231 sb.append("size:");
2232 sb.append(mIntents.length);
2233 } else {
2234 final int size = mIntents.length;
2235 sb.append("[");
2236 String sep = "";
2237 for (int i = 0; i < size; i++) {
2238 sb.append(sep);
2239 sep = ", ";
2240 sb.append(mIntents[i]);
2241 sb.append("/");
2242 sb.append(mIntentPersistableExtrases[i]);
2243 }
2244 sb.append("]");
2245 }
2246 }
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002247
Makoto Onuki6208c672017-10-02 16:20:35 -07002248 addIndentOrComma(sb, indent);
2249
2250 sb.append("extras=");
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002251 sb.append(mExtras);
2252
2253 if (includeInternalData) {
Makoto Onuki6208c672017-10-02 16:20:35 -07002254 addIndentOrComma(sb, indent);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002255
Makoto Onuki6208c672017-10-02 16:20:35 -07002256 sb.append("iconRes=");
Makoto Onuki157b1622016-06-02 16:13:10 -07002257 sb.append(mIconResId);
2258 sb.append("[");
2259 sb.append(mIconResName);
2260 sb.append("]");
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002261
2262 sb.append(", bitmapPath=");
2263 sb.append(mBitmapPath);
2264 }
2265
2266 sb.append("}");
2267 return sb.toString();
2268 }
2269
2270 /** @hide */
Makoto Onukiabe84422016-04-07 09:41:19 -07002271 public ShortcutInfo(
Makoto Onuki22fcc682016-05-17 14:52:19 -07002272 @UserIdInt int userId, String id, String packageName, ComponentName activity,
Makoto Onuki157b1622016-06-02 16:13:10 -07002273 Icon icon, CharSequence title, int titleResId, String titleResName,
2274 CharSequence text, int textResId, String textResName,
2275 CharSequence disabledMessage, int disabledMessageResId, String disabledMessageResName,
Makoto Onuki440a1ea2016-07-20 14:21:18 -07002276 Set<String> categories, Intent[] intentsWithExtras, int rank, PersistableBundle extras,
2277 long lastChangedTimestamp,
Mehdi Alizadehebb4b602019-02-05 15:52:18 -08002278 int flags, int iconResId, String iconResName, String bitmapPath, int disabledReason,
2279 Person[] persons) {
Makoto Onukiabe84422016-04-07 09:41:19 -07002280 mUserId = userId;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002281 mId = id;
2282 mPackageName = packageName;
Makoto Onuki22fcc682016-05-17 14:52:19 -07002283 mActivity = activity;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002284 mIcon = icon;
2285 mTitle = title;
Makoto Onuki20c95f82016-05-11 16:51:01 -07002286 mTitleResId = titleResId;
Makoto Onuki157b1622016-06-02 16:13:10 -07002287 mTitleResName = titleResName;
Makoto Onukie3ae7ec2016-03-29 15:45:25 -07002288 mText = text;
Makoto Onuki20c95f82016-05-11 16:51:01 -07002289 mTextResId = textResId;
Makoto Onuki157b1622016-06-02 16:13:10 -07002290 mTextResName = textResName;
Makoto Onuki20c95f82016-05-11 16:51:01 -07002291 mDisabledMessage = disabledMessage;
2292 mDisabledMessageResId = disabledMessageResId;
Makoto Onuki157b1622016-06-02 16:13:10 -07002293 mDisabledMessageResName = disabledMessageResName;
Makoto Onukidf6da042016-06-16 09:51:40 -07002294 mCategories = cloneCategories(categories);
Makoto Onuki440a1ea2016-07-20 14:21:18 -07002295 mIntents = cloneIntents(intentsWithExtras);
2296 fixUpIntentExtras();
Makoto Onuki20c95f82016-05-11 16:51:01 -07002297 mRank = rank;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002298 mExtras = extras;
2299 mLastChangedTimestamp = lastChangedTimestamp;
2300 mFlags = flags;
Makoto Onuki157b1622016-06-02 16:13:10 -07002301 mIconResId = iconResId;
2302 mIconResName = iconResName;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002303 mBitmapPath = bitmapPath;
Makoto Onukia4f89b12017-10-05 10:37:55 -07002304 mDisabledReason = disabledReason;
Mehdi Alizadehebb4b602019-02-05 15:52:18 -08002305 mPersons = persons;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002306 }
2307}