blob: b1553250d638ab6c64df3830cfdef668f9ce2700 [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;
Makoto Onukia4f89b12017-10-05 10:37:55 -070021import android.annotation.TestApi;
Mathew Inwood5c0d3542018-08-14 13:54:31 +010022import android.annotation.UnsupportedAppUsage;
Makoto Onukiabe84422016-04-07 09:41:19 -070023import android.annotation.UserIdInt;
Mehdi Alizadeh14242af2018-12-20 20:11:35 -080024import android.app.Person;
Makoto Onuki347a6bd2016-07-19 11:13:08 -070025import android.app.TaskStackBuilder;
Makoto Onuki6f7362d92016-03-04 13:39:41 -080026import android.content.ComponentName;
27import android.content.Context;
28import android.content.Intent;
Makoto Onuki4a910962016-07-07 13:57:34 -070029import android.content.pm.LauncherApps.ShortcutQuery;
Makoto Onuki20c95f82016-05-11 16:51:01 -070030import android.content.res.Resources;
Makoto Onuki157b1622016-06-02 16:13:10 -070031import android.content.res.Resources.NotFoundException;
Makoto Onuki4a910962016-07-07 13:57:34 -070032import android.graphics.Bitmap;
Makoto Onuki6f7362d92016-03-04 13:39:41 -080033import android.graphics.drawable.Icon;
Mathew Inwood8c854f82018-09-14 12:35:36 +010034import android.os.Build;
Makoto Onuki55046222016-03-08 10:49:47 -080035import android.os.Bundle;
Makoto Onuki6f7362d92016-03-04 13:39:41 -080036import android.os.Parcel;
37import android.os.Parcelable;
38import android.os.PersistableBundle;
39import android.os.UserHandle;
Makoto Onukidf6da042016-06-16 09:51:40 -070040import android.text.TextUtils;
Makoto Onukibe73a802016-04-15 14:46:35 -070041import android.util.ArraySet;
Makoto Onuki157b1622016-06-02 16:13:10 -070042import android.util.Log;
Makoto Onuki6f7362d92016-03-04 13:39:41 -080043
Makoto Onuki157b1622016-06-02 16:13:10 -070044import com.android.internal.annotations.VisibleForTesting;
Makoto Onuki6f7362d92016-03-04 13:39:41 -080045import com.android.internal.util.Preconditions;
46
47import java.lang.annotation.Retention;
48import java.lang.annotation.RetentionPolicy;
Makoto Onukib5a012f2016-06-21 11:13:53 -070049import java.util.List;
Makoto Onukibe73a802016-04-15 14:46:35 -070050import java.util.Set;
Makoto Onuki6f7362d92016-03-04 13:39:41 -080051
52/**
Kevin Hufnagle68d699d2016-10-14 19:04:51 -070053 * Represents a shortcut that can be published via {@link ShortcutManager}.
Makoto Onuki6f7362d92016-03-04 13:39:41 -080054 *
Makoto Onuki4a910962016-07-07 13:57:34 -070055 * @see ShortcutManager
Makoto Onuki6f7362d92016-03-04 13:39:41 -080056 */
Jeff Sharkey70168dd2016-03-30 21:47:16 -060057public final class ShortcutInfo implements Parcelable {
Makoto Onuki157b1622016-06-02 16:13:10 -070058 static final String TAG = "Shortcut";
59
60 private static final String RES_TYPE_STRING = "string";
61
62 private static final String ANDROID_PACKAGE_NAME = "android";
63
Makoto Onuki9e1f5592016-06-08 12:30:23 -070064 private static final int IMPLICIT_RANK_MASK = 0x7fffffff;
65
66 private static final int RANK_CHANGED_BIT = ~IMPLICIT_RANK_MASK;
67
68 /** @hide */
69 public static final int RANK_NOT_SET = Integer.MAX_VALUE;
70
Makoto Onuki157b1622016-06-02 16:13:10 -070071 /** @hide */
Makoto Onuki6f7362d92016-03-04 13:39:41 -080072 public static final int FLAG_DYNAMIC = 1 << 0;
73
Makoto Onuki157b1622016-06-02 16:13:10 -070074 /** @hide */
Makoto Onuki6f7362d92016-03-04 13:39:41 -080075 public static final int FLAG_PINNED = 1 << 1;
76
Makoto Onuki157b1622016-06-02 16:13:10 -070077 /** @hide */
Makoto Onuki6f7362d92016-03-04 13:39:41 -080078 public static final int FLAG_HAS_ICON_RES = 1 << 2;
79
Makoto Onuki157b1622016-06-02 16:13:10 -070080 /** @hide */
Makoto Onuki6f7362d92016-03-04 13:39:41 -080081 public static final int FLAG_HAS_ICON_FILE = 1 << 3;
82
Makoto Onuki157b1622016-06-02 16:13:10 -070083 /** @hide */
Makoto Onuki55046222016-03-08 10:49:47 -080084 public static final int FLAG_KEY_FIELDS_ONLY = 1 << 4;
85
Makoto Onuki157b1622016-06-02 16:13:10 -070086 /** @hide */
Makoto Onuki22fcc682016-05-17 14:52:19 -070087 public static final int FLAG_MANIFEST = 1 << 5;
Makoto Onuki20c95f82016-05-11 16:51:01 -070088
Makoto Onuki157b1622016-06-02 16:13:10 -070089 /** @hide */
Makoto Onuki20c95f82016-05-11 16:51:01 -070090 public static final int FLAG_DISABLED = 1 << 6;
91
Makoto Onuki157b1622016-06-02 16:13:10 -070092 /** @hide */
Makoto Onuki20c95f82016-05-11 16:51:01 -070093 public static final int FLAG_STRINGS_RESOLVED = 1 << 7;
94
Makoto Onuki157b1622016-06-02 16:13:10 -070095 /** @hide */
Makoto Onuki22fcc682016-05-17 14:52:19 -070096 public static final int FLAG_IMMUTABLE = 1 << 8;
97
Makoto Onuki6f7362d92016-03-04 13:39:41 -080098 /** @hide */
Hyunyoung Songe4179e22017-03-01 12:51:26 -080099 public static final int FLAG_ADAPTIVE_BITMAP = 1 << 9;
Hyunyoung Songf281e7a2017-02-13 10:57:42 -0800100
101 /** @hide */
Makoto Onukibf563b62017-05-04 10:25:30 -0700102 public static final int FLAG_RETURNED_BY_SERVICE = 1 << 10;
103
Makoto Onuki475c3652017-05-08 14:29:03 -0700104 /** @hide When this is set, the bitmap icon is waiting to be saved. */
105 public static final int FLAG_ICON_FILE_PENDING_SAVE = 1 << 11;
106
Makoto Onukia4f89b12017-10-05 10:37:55 -0700107 /**
108 * "Shadow" shortcuts are the ones that are restored, but the owner package hasn't been
109 * installed yet.
110 * @hide
111 */
112 public static final int FLAG_SHADOW = 1 << 12;
113
Makoto Onukibf563b62017-05-04 10:25:30 -0700114 /** @hide */
Mehdi Alizadeh14242af2018-12-20 20:11:35 -0800115 public static final int FLAG_LONG_LIVED = 1 << 13;
116
117 /** @hide */
Jeff Sharkeyce8db992017-12-13 20:05:05 -0700118 @IntDef(flag = true, prefix = { "FLAG_" }, value = {
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800119 FLAG_DYNAMIC,
120 FLAG_PINNED,
121 FLAG_HAS_ICON_RES,
122 FLAG_HAS_ICON_FILE,
Makoto Onuki55046222016-03-08 10:49:47 -0800123 FLAG_KEY_FIELDS_ONLY,
Makoto Onuki22fcc682016-05-17 14:52:19 -0700124 FLAG_MANIFEST,
Makoto Onuki20c95f82016-05-11 16:51:01 -0700125 FLAG_DISABLED,
126 FLAG_STRINGS_RESOLVED,
Makoto Onuki22fcc682016-05-17 14:52:19 -0700127 FLAG_IMMUTABLE,
Hyunyoung Songe4179e22017-03-01 12:51:26 -0800128 FLAG_ADAPTIVE_BITMAP,
Makoto Onuki475c3652017-05-08 14:29:03 -0700129 FLAG_RETURNED_BY_SERVICE,
130 FLAG_ICON_FILE_PENDING_SAVE,
Mehdi Alizadeh14242af2018-12-20 20:11:35 -0800131 FLAG_SHADOW,
132 FLAG_LONG_LIVED,
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800133 })
134 @Retention(RetentionPolicy.SOURCE)
135 public @interface ShortcutFlags {}
136
137 // Cloning options.
138
Makoto Onuki157b1622016-06-02 16:13:10 -0700139 /** @hide */
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800140 private static final int CLONE_REMOVE_ICON = 1 << 0;
141
Makoto Onuki157b1622016-06-02 16:13:10 -0700142 /** @hide */
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800143 private static final int CLONE_REMOVE_INTENT = 1 << 1;
144
Makoto Onuki157b1622016-06-02 16:13:10 -0700145 /** @hide */
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800146 public static final int CLONE_REMOVE_NON_KEY_INFO = 1 << 2;
147
Makoto Onuki157b1622016-06-02 16:13:10 -0700148 /** @hide */
149 public static final int CLONE_REMOVE_RES_NAMES = 1 << 3;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800150
Makoto Onuki157b1622016-06-02 16:13:10 -0700151 /** @hide */
152 public static final int CLONE_REMOVE_FOR_CREATOR = CLONE_REMOVE_ICON | CLONE_REMOVE_RES_NAMES;
153
154 /** @hide */
155 public static final int CLONE_REMOVE_FOR_LAUNCHER = CLONE_REMOVE_ICON | CLONE_REMOVE_INTENT
156 | CLONE_REMOVE_RES_NAMES;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800157
158 /** @hide */
Makoto Onukia01f4f02016-12-15 15:58:41 -0800159 public static final int CLONE_REMOVE_FOR_LAUNCHER_APPROVAL = CLONE_REMOVE_INTENT
160 | CLONE_REMOVE_RES_NAMES;
161
162 /** @hide */
Jeff Sharkeyce8db992017-12-13 20:05:05 -0700163 @IntDef(flag = true, prefix = { "CLONE_" }, value = {
164 CLONE_REMOVE_ICON,
165 CLONE_REMOVE_INTENT,
166 CLONE_REMOVE_NON_KEY_INFO,
167 CLONE_REMOVE_RES_NAMES,
168 CLONE_REMOVE_FOR_CREATOR,
169 CLONE_REMOVE_FOR_LAUNCHER
170 })
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800171 @Retention(RetentionPolicy.SOURCE)
172 public @interface CloneFlags {}
173
Makoto Onukib6d35232016-04-04 15:57:17 -0700174 /**
Makoto Onukia4f89b12017-10-05 10:37:55 -0700175 * Shortcut is not disabled.
176 */
177 public static final int DISABLED_REASON_NOT_DISABLED = 0;
178
179 /**
180 * Shortcut has been disabled by the publisher app with the
181 * {@link ShortcutManager#disableShortcuts(List)} API.
182 */
183 public static final int DISABLED_REASON_BY_APP = 1;
184
185 /**
186 * Shortcut has been disabled due to changes to the publisher app. (e.g. a manifest shortcut
187 * no longer exists.)
188 */
189 public static final int DISABLED_REASON_APP_CHANGED = 2;
190
191 /**
Makoto Onuki5482a8e62018-01-09 10:31:08 -0800192 * Shortcut is disabled for an unknown reason.
193 */
194 public static final int DISABLED_REASON_UNKNOWN = 3;
195
196 /**
Makoto Onukia4f89b12017-10-05 10:37:55 -0700197 * A disabled reason that's equal to or bigger than this is due to backup and restore issue.
198 * A shortcut with such a reason wil be visible to the launcher, but not to the publisher.
199 * ({@link #isVisibleToPublisher()} will be false.)
200 */
201 private static final int DISABLED_REASON_RESTORE_ISSUE_START = 100;
202
203 /**
204 * Shortcut has been restored from the previous device, but the publisher app on the current
205 * device is of a lower version. The shortcut will not be usable until the app is upgraded to
206 * the same version or higher.
207 */
208 public static final int DISABLED_REASON_VERSION_LOWER = 100;
209
210 /**
211 * Shortcut has not been restored because the publisher app does not support backup and restore.
212 */
213 public static final int DISABLED_REASON_BACKUP_NOT_SUPPORTED = 101;
214
215 /**
216 * Shortcut has not been restored because the publisher app's signature has changed.
217 */
218 public static final int DISABLED_REASON_SIGNATURE_MISMATCH = 102;
219
220 /**
221 * Shortcut has not been restored for unknown reason.
222 */
223 public static final int DISABLED_REASON_OTHER_RESTORE_ISSUE = 103;
224
225 /** @hide */
Jeff Sharkeyce8db992017-12-13 20:05:05 -0700226 @IntDef(prefix = { "DISABLED_REASON_" }, value = {
Makoto Onukia4f89b12017-10-05 10:37:55 -0700227 DISABLED_REASON_NOT_DISABLED,
228 DISABLED_REASON_BY_APP,
229 DISABLED_REASON_APP_CHANGED,
Makoto Onuki5482a8e62018-01-09 10:31:08 -0800230 DISABLED_REASON_UNKNOWN,
Makoto Onukia4f89b12017-10-05 10:37:55 -0700231 DISABLED_REASON_VERSION_LOWER,
232 DISABLED_REASON_BACKUP_NOT_SUPPORTED,
233 DISABLED_REASON_SIGNATURE_MISMATCH,
234 DISABLED_REASON_OTHER_RESTORE_ISSUE,
Jeff Sharkeyce8db992017-12-13 20:05:05 -0700235 })
Makoto Onukia4f89b12017-10-05 10:37:55 -0700236 @Retention(RetentionPolicy.SOURCE)
237 public @interface DisabledReason{}
238
Makoto Onukib1588c02017-10-12 15:11:45 -0700239 /**
240 * Return a label for disabled reasons, which are *not* supposed to be shown to the user.
241 * @hide
242 */
243 public static String getDisabledReasonDebugString(@DisabledReason int disabledReason) {
Makoto Onukia4f89b12017-10-05 10:37:55 -0700244 switch (disabledReason) {
245 case DISABLED_REASON_NOT_DISABLED:
246 return "[Not disabled]";
247 case DISABLED_REASON_BY_APP:
248 return "[Disabled: by app]";
249 case DISABLED_REASON_APP_CHANGED:
250 return "[Disabled: app changed]";
251 case DISABLED_REASON_VERSION_LOWER:
252 return "[Disabled: lower version]";
253 case DISABLED_REASON_BACKUP_NOT_SUPPORTED:
254 return "[Disabled: backup not supported]";
255 case DISABLED_REASON_SIGNATURE_MISMATCH:
256 return "[Disabled: signature mismatch]";
257 case DISABLED_REASON_OTHER_RESTORE_ISSUE:
258 return "[Disabled: unknown restore issue]";
259 }
260 return "[Disabled: unknown reason:" + disabledReason + "]";
261 }
262
Makoto Onukib1588c02017-10-12 15:11:45 -0700263 /**
264 * Return a label for a disabled reason for shortcuts that are disabled due to a backup and
265 * restore issue. If the reason is not due to backup & restore, then it'll return null.
266 *
267 * This method returns localized, user-facing strings, which will be returned by
268 * {@link #getDisabledMessage()}.
269 *
270 * @hide
271 */
272 public static String getDisabledReasonForRestoreIssue(Context context,
273 @DisabledReason int disabledReason) {
274 final Resources res = context.getResources();
275
276 switch (disabledReason) {
277 case DISABLED_REASON_VERSION_LOWER:
278 return res.getString(
279 com.android.internal.R.string.shortcut_restored_on_lower_version);
280 case DISABLED_REASON_BACKUP_NOT_SUPPORTED:
281 return res.getString(
282 com.android.internal.R.string.shortcut_restore_not_supported);
283 case DISABLED_REASON_SIGNATURE_MISMATCH:
284 return res.getString(
285 com.android.internal.R.string.shortcut_restore_signature_mismatch);
286 case DISABLED_REASON_OTHER_RESTORE_ISSUE:
287 return res.getString(
288 com.android.internal.R.string.shortcut_restore_unknown_issue);
Makoto Onuki5482a8e62018-01-09 10:31:08 -0800289 case DISABLED_REASON_UNKNOWN:
290 return res.getString(
291 com.android.internal.R.string.shortcut_disabled_reason_unknown);
Makoto Onukib1588c02017-10-12 15:11:45 -0700292 }
293 return null;
294 }
295
Makoto Onukia4f89b12017-10-05 10:37:55 -0700296 /** @hide */
297 public static boolean isDisabledForRestoreIssue(@DisabledReason int disabledReason) {
298 return disabledReason >= DISABLED_REASON_RESTORE_ISSUE_START;
299 }
300
301 /**
Makoto Onuki4a910962016-07-07 13:57:34 -0700302 * Shortcut category for messaging related actions, such as chat.
Makoto Onukib6d35232016-04-04 15:57:17 -0700303 */
304 public static final String SHORTCUT_CATEGORY_CONVERSATION = "android.shortcut.conversation";
305
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800306 private final String mId;
307
308 @NonNull
309 private final String mPackageName;
310
311 @Nullable
Makoto Onuki22fcc682016-05-17 14:52:19 -0700312 private ComponentName mActivity;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800313
314 @Nullable
315 private Icon mIcon;
316
Makoto Onuki20c95f82016-05-11 16:51:01 -0700317 private int mTitleResId;
318
Makoto Onuki157b1622016-06-02 16:13:10 -0700319 private String mTitleResName;
320
Makoto Onuki20c95f82016-05-11 16:51:01 -0700321 @Nullable
Makoto Onuki22fcc682016-05-17 14:52:19 -0700322 private CharSequence mTitle;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800323
Makoto Onuki20c95f82016-05-11 16:51:01 -0700324 private int mTextResId;
325
Makoto Onuki157b1622016-06-02 16:13:10 -0700326 private String mTextResName;
327
Makoto Onukie3ae7ec2016-03-29 15:45:25 -0700328 @Nullable
Makoto Onuki22fcc682016-05-17 14:52:19 -0700329 private CharSequence mText;
Makoto Onukie3ae7ec2016-03-29 15:45:25 -0700330
Makoto Onuki20c95f82016-05-11 16:51:01 -0700331 private int mDisabledMessageResId;
332
Makoto Onuki157b1622016-06-02 16:13:10 -0700333 private String mDisabledMessageResName;
334
Makoto Onuki20c95f82016-05-11 16:51:01 -0700335 @Nullable
Makoto Onuki22fcc682016-05-17 14:52:19 -0700336 private CharSequence mDisabledMessage;
Makoto Onuki20c95f82016-05-11 16:51:01 -0700337
338 @Nullable
Makoto Onukibe73a802016-04-15 14:46:35 -0700339 private ArraySet<String> mCategories;
Makoto Onukib6d35232016-04-04 15:57:17 -0700340
Makoto Onuki55046222016-03-08 10:49:47 -0800341 /**
Makoto Onuki440a1ea2016-07-20 14:21:18 -0700342 * Intents *with extras removed*.
Makoto Onuki55046222016-03-08 10:49:47 -0800343 */
Makoto Onuki20c95f82016-05-11 16:51:01 -0700344 @Nullable
Makoto Onuki440a1ea2016-07-20 14:21:18 -0700345 private Intent[] mIntents;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800346
Makoto Onuki55046222016-03-08 10:49:47 -0800347 /**
Makoto Onuki440a1ea2016-07-20 14:21:18 -0700348 * Extras for the intents.
Makoto Onuki55046222016-03-08 10:49:47 -0800349 */
Makoto Onuki20c95f82016-05-11 16:51:01 -0700350 @Nullable
Makoto Onuki440a1ea2016-07-20 14:21:18 -0700351 private PersistableBundle[] mIntentPersistableExtrases;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800352
Mehdi Alizadeh14242af2018-12-20 20:11:35 -0800353 @Nullable
354 private Person[] mPersons;
355
Makoto Onuki20c95f82016-05-11 16:51:01 -0700356 private int mRank;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800357
Makoto Onuki9e1f5592016-06-08 12:30:23 -0700358 /**
359 * Internally used for auto-rank-adjustment.
360 *
361 * RANK_CHANGED_BIT is used to denote that the rank of a shortcut is changing.
362 * The rest of the bits are used to denote the order in which shortcuts are passed to
363 * APIs, which is used to preserve the argument order when ranks are tie.
364 */
365 private int mImplicitRank;
366
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800367 @Nullable
368 private PersistableBundle mExtras;
369
370 private long mLastChangedTimestamp;
371
372 // Internal use only.
373 @ShortcutFlags
374 private int mFlags;
375
376 // Internal use only.
Makoto Onuki157b1622016-06-02 16:13:10 -0700377 private int mIconResId;
378
379 private String mIconResName;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800380
381 // Internal use only.
382 @Nullable
383 private String mBitmapPath;
384
Makoto Onukiabe84422016-04-07 09:41:19 -0700385 private final int mUserId;
386
Makoto Onukia4f89b12017-10-05 10:37:55 -0700387 /** @hide */
388 public static final int VERSION_CODE_UNKNOWN = -1;
389
390 private int mDisabledReason;
391
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800392 private ShortcutInfo(Builder b) {
Makoto Onukiabe84422016-04-07 09:41:19 -0700393 mUserId = b.mContext.getUserId();
394
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800395 mId = Preconditions.checkStringNotEmpty(b.mId, "Shortcut ID must be provided");
396
397 // Note we can't do other null checks here because SM.updateShortcuts() takes partial
398 // information.
399 mPackageName = b.mContext.getPackageName();
Makoto Onuki22fcc682016-05-17 14:52:19 -0700400 mActivity = b.mActivity;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800401 mIcon = b.mIcon;
402 mTitle = b.mTitle;
Makoto Onuki20c95f82016-05-11 16:51:01 -0700403 mTitleResId = b.mTitleResId;
Makoto Onukie3ae7ec2016-03-29 15:45:25 -0700404 mText = b.mText;
Makoto Onuki20c95f82016-05-11 16:51:01 -0700405 mTextResId = b.mTextResId;
406 mDisabledMessage = b.mDisabledMessage;
407 mDisabledMessageResId = b.mDisabledMessageResId;
Makoto Onukidf6da042016-06-16 09:51:40 -0700408 mCategories = cloneCategories(b.mCategories);
Makoto Onuki440a1ea2016-07-20 14:21:18 -0700409 mIntents = cloneIntents(b.mIntents);
410 fixUpIntentExtras();
Mehdi Alizadeh14242af2018-12-20 20:11:35 -0800411 mPersons = clonePersons(b.mPersons);
412 if (b.mIsLongLived) {
413 setLongLived();
414 }
Makoto Onuki20c95f82016-05-11 16:51:01 -0700415 mRank = b.mRank;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800416 mExtras = b.mExtras;
417 updateTimestamp();
418 }
419
Makoto Onuki440a1ea2016-07-20 14:21:18 -0700420 /**
421 * Extract extras from {@link #mIntents} and set them to {@link #mIntentPersistableExtrases}
422 * as {@link PersistableBundle}, and remove extras from the original intents.
423 */
424 private void fixUpIntentExtras() {
425 if (mIntents == null) {
426 mIntentPersistableExtrases = null;
427 return;
428 }
429 mIntentPersistableExtrases = new PersistableBundle[mIntents.length];
430 for (int i = 0; i < mIntents.length; i++) {
431 final Intent intent = mIntents[i];
432 final Bundle extras = intent.getExtras();
433 if (extras == null) {
434 mIntentPersistableExtrases[i] = null;
435 } else {
436 mIntentPersistableExtrases[i] = new PersistableBundle(extras);
437 intent.replaceExtras((Bundle) null);
438 }
439 }
440 }
441
442 private static ArraySet<String> cloneCategories(Set<String> source) {
Makoto Onukidf6da042016-06-16 09:51:40 -0700443 if (source == null) {
444 return null;
445 }
446 final ArraySet<String> ret = new ArraySet<>(source.size());
447 for (CharSequence s : source) {
448 if (!TextUtils.isEmpty(s)) {
449 ret.add(s.toString().intern());
450 }
451 }
452 return ret;
Makoto Onukib6d35232016-04-04 15:57:17 -0700453 }
454
Makoto Onuki440a1ea2016-07-20 14:21:18 -0700455 private static Intent[] cloneIntents(Intent[] intents) {
456 if (intents == null) {
457 return null;
458 }
459 final Intent[] ret = new Intent[intents.length];
460 for (int i = 0; i < ret.length; i++) {
461 if (intents[i] != null) {
462 ret[i] = new Intent(intents[i]);
463 }
464 }
465 return ret;
466 }
467
468 private static PersistableBundle[] clonePersistableBundle(PersistableBundle[] bundle) {
469 if (bundle == null) {
470 return null;
471 }
472 final PersistableBundle[] ret = new PersistableBundle[bundle.length];
473 for (int i = 0; i < ret.length; i++) {
474 if (bundle[i] != null) {
475 ret[i] = new PersistableBundle(bundle[i]);
476 }
477 }
478 return ret;
479 }
480
Mehdi Alizadeh14242af2018-12-20 20:11:35 -0800481 private static Person[] clonePersons(Person[] persons) {
482 if (persons == null) {
483 return null;
484 }
485 final Person[] ret = new Person[persons.length];
486 for (int i = 0; i < ret.length; i++) {
487 if (persons[i] != null) {
488 // Don't need to keep the icon, remove it to save space
489 ret[i] = persons[i].toBuilder().setIcon(null).build();
490 }
491 }
492 return ret;
493 }
494
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800495 /**
496 * Throws if any of the mandatory fields is not set.
497 *
498 * @hide
499 */
Makoto Onuki106ff7a2016-12-01 10:17:57 -0800500 public void enforceMandatoryFields(boolean forPinned) {
Makoto Onukie3ae7ec2016-03-29 15:45:25 -0700501 Preconditions.checkStringNotEmpty(mId, "Shortcut ID must be provided");
Makoto Onuki106ff7a2016-12-01 10:17:57 -0800502 if (!forPinned) {
503 Preconditions.checkNotNull(mActivity, "Activity must be provided");
504 }
Makoto Onuki20c95f82016-05-11 16:51:01 -0700505 if (mTitle == null && mTitleResId == 0) {
Makoto Onukia1d38b32016-06-10 15:32:26 -0700506 throw new IllegalArgumentException("Short label must be provided");
Makoto Onuki20c95f82016-05-11 16:51:01 -0700507 }
Makoto Onuki99302b52017-03-29 12:42:26 -0700508 Preconditions.checkNotNull(mIntents, "Shortcut Intent must be provided");
509 Preconditions.checkArgument(mIntents.length > 0, "Shortcut Intent must be provided");
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800510 }
511
512 /**
513 * Copy constructor.
514 */
515 private ShortcutInfo(ShortcutInfo source, @CloneFlags int cloneFlags) {
Makoto Onukiabe84422016-04-07 09:41:19 -0700516 mUserId = source.mUserId;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800517 mId = source.mId;
518 mPackageName = source.mPackageName;
Makoto Onuki4d6b87f2016-06-17 13:47:40 -0700519 mActivity = source.mActivity;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800520 mFlags = source.mFlags;
521 mLastChangedTimestamp = source.mLastChangedTimestamp;
Makoto Onukia4f89b12017-10-05 10:37:55 -0700522 mDisabledReason = source.mDisabledReason;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800523
Makoto Onukib6d35232016-04-04 15:57:17 -0700524 // Just always keep it since it's cheep.
Makoto Onuki157b1622016-06-02 16:13:10 -0700525 mIconResId = source.mIconResId;
Makoto Onukib6d35232016-04-04 15:57:17 -0700526
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800527 if ((cloneFlags & CLONE_REMOVE_NON_KEY_INFO) == 0) {
Makoto Onuki55046222016-03-08 10:49:47 -0800528
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800529 if ((cloneFlags & CLONE_REMOVE_ICON) == 0) {
530 mIcon = source.mIcon;
Makoto Onuki7a6a05f2016-03-10 17:01:08 -0800531 mBitmapPath = source.mBitmapPath;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800532 }
533
534 mTitle = source.mTitle;
Makoto Onuki20c95f82016-05-11 16:51:01 -0700535 mTitleResId = source.mTitleResId;
Makoto Onukie3ae7ec2016-03-29 15:45:25 -0700536 mText = source.mText;
Makoto Onuki20c95f82016-05-11 16:51:01 -0700537 mTextResId = source.mTextResId;
538 mDisabledMessage = source.mDisabledMessage;
539 mDisabledMessageResId = source.mDisabledMessageResId;
Makoto Onukidf6da042016-06-16 09:51:40 -0700540 mCategories = cloneCategories(source.mCategories);
Mehdi Alizadeh14242af2018-12-20 20:11:35 -0800541 mPersons = clonePersons(source.mPersons);
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800542 if ((cloneFlags & CLONE_REMOVE_INTENT) == 0) {
Makoto Onuki440a1ea2016-07-20 14:21:18 -0700543 mIntents = cloneIntents(source.mIntents);
544 mIntentPersistableExtrases =
545 clonePersistableBundle(source.mIntentPersistableExtrases);
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800546 }
Makoto Onuki20c95f82016-05-11 16:51:01 -0700547 mRank = source.mRank;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800548 mExtras = source.mExtras;
Makoto Onuki157b1622016-06-02 16:13:10 -0700549
550 if ((cloneFlags & CLONE_REMOVE_RES_NAMES) == 0) {
551 mTitleResName = source.mTitleResName;
552 mTextResName = source.mTextResName;
553 mDisabledMessageResName = source.mDisabledMessageResName;
554 mIconResName = source.mIconResName;
555 }
Makoto Onuki55046222016-03-08 10:49:47 -0800556 } else {
557 // Set this bit.
558 mFlags |= FLAG_KEY_FIELDS_ONLY;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800559 }
560 }
561
Makoto Onuki157b1622016-06-02 16:13:10 -0700562 /**
563 * Load a string resource from the publisher app.
564 *
565 * @param resId resource ID
566 * @param defValue default value to be returned when the specified resource isn't found.
567 */
568 private CharSequence getResourceString(Resources res, int resId, CharSequence defValue) {
569 try {
570 return res.getString(resId);
571 } catch (NotFoundException e) {
572 Log.e(TAG, "Resource for ID=" + resId + " not found in package " + mPackageName);
573 return defValue;
574 }
575 }
576
577 /**
578 * Load the string resources for the text fields and set them to the actual value fields.
579 * This will set {@link #FLAG_STRINGS_RESOLVED}.
580 *
581 * @param res {@link Resources} for the publisher. Must have been loaded with
582 * {@link PackageManager#getResourcesForApplicationAsUser}.
583 *
584 * @hide
585 */
586 public void resolveResourceStrings(@NonNull Resources res) {
Makoto Onuki20c95f82016-05-11 16:51:01 -0700587 mFlags |= FLAG_STRINGS_RESOLVED;
588
589 if ((mTitleResId == 0) && (mTextResId == 0) && (mDisabledMessageResId == 0)) {
590 return; // Bail early.
591 }
Makoto Onuki20c95f82016-05-11 16:51:01 -0700592
593 if (mTitleResId != 0) {
Makoto Onuki157b1622016-06-02 16:13:10 -0700594 mTitle = getResourceString(res, mTitleResId, mTitle);
Makoto Onuki20c95f82016-05-11 16:51:01 -0700595 }
596 if (mTextResId != 0) {
Makoto Onuki157b1622016-06-02 16:13:10 -0700597 mText = getResourceString(res, mTextResId, mText);
Makoto Onuki20c95f82016-05-11 16:51:01 -0700598 }
599 if (mDisabledMessageResId != 0) {
Makoto Onuki157b1622016-06-02 16:13:10 -0700600 mDisabledMessage = getResourceString(res, mDisabledMessageResId, mDisabledMessage);
Makoto Onuki20c95f82016-05-11 16:51:01 -0700601 }
602 }
603
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800604 /**
Makoto Onuki157b1622016-06-02 16:13:10 -0700605 * Look up resource name for a given resource ID.
606 *
607 * @return a simple resource name (e.g. "text_1") when {@code withType} is false, or with the
608 * type (e.g. "string/text_1").
609 *
610 * @hide
611 */
612 @VisibleForTesting
613 public static String lookUpResourceName(@NonNull Resources res, int resId, boolean withType,
614 @NonNull String packageName) {
615 if (resId == 0) {
616 return null;
617 }
618 try {
619 final String fullName = res.getResourceName(resId);
620
621 if (ANDROID_PACKAGE_NAME.equals(getResourcePackageName(fullName))) {
622 // If it's a framework resource, the value won't change, so just return the ID
623 // value as a string.
624 return String.valueOf(resId);
625 }
626 return withType ? getResourceTypeAndEntryName(fullName)
627 : getResourceEntryName(fullName);
628 } catch (NotFoundException e) {
629 Log.e(TAG, "Resource name for ID=" + resId + " not found in package " + packageName
630 + ". Resource IDs may change when the application is upgraded, and the system"
631 + " may not be able to find the correct resource.");
632 return null;
633 }
634 }
635
636 /**
637 * Extract the package name from a fully-donated resource name.
638 * e.g. "com.android.app1:drawable/icon1" -> "com.android.app1"
639 * @hide
640 */
641 @VisibleForTesting
642 public static String getResourcePackageName(@NonNull String fullResourceName) {
643 final int p1 = fullResourceName.indexOf(':');
644 if (p1 < 0) {
645 return null;
646 }
647 return fullResourceName.substring(0, p1);
648 }
649
650 /**
651 * Extract the type name from a fully-donated resource name.
652 * e.g. "com.android.app1:drawable/icon1" -> "drawable"
653 * @hide
654 */
655 @VisibleForTesting
656 public static String getResourceTypeName(@NonNull String fullResourceName) {
657 final int p1 = fullResourceName.indexOf(':');
658 if (p1 < 0) {
659 return null;
660 }
661 final int p2 = fullResourceName.indexOf('/', p1 + 1);
662 if (p2 < 0) {
663 return null;
664 }
665 return fullResourceName.substring(p1 + 1, p2);
666 }
667
668 /**
669 * Extract the type name + the entry name from a fully-donated resource name.
670 * e.g. "com.android.app1:drawable/icon1" -> "drawable/icon1"
671 * @hide
672 */
673 @VisibleForTesting
674 public static String getResourceTypeAndEntryName(@NonNull String fullResourceName) {
675 final int p1 = fullResourceName.indexOf(':');
676 if (p1 < 0) {
677 return null;
678 }
679 return fullResourceName.substring(p1 + 1);
680 }
681
682 /**
683 * Extract the entry name from a fully-donated resource name.
684 * e.g. "com.android.app1:drawable/icon1" -> "icon1"
685 * @hide
686 */
687 @VisibleForTesting
688 public static String getResourceEntryName(@NonNull String fullResourceName) {
689 final int p1 = fullResourceName.indexOf('/');
690 if (p1 < 0) {
691 return null;
692 }
693 return fullResourceName.substring(p1 + 1);
694 }
695
696 /**
697 * Return the resource ID for a given resource ID.
698 *
699 * Basically its' a wrapper over {@link Resources#getIdentifier(String, String, String)}, except
700 * if {@code resourceName} is an integer then it'll just return its value. (Which also the
701 * aforementioned method would do internally, but not documented, so doing here explicitly.)
702 *
703 * @param res {@link Resources} for the publisher. Must have been loaded with
704 * {@link PackageManager#getResourcesForApplicationAsUser}.
705 *
706 * @hide
707 */
708 @VisibleForTesting
709 public static int lookUpResourceId(@NonNull Resources res, @Nullable String resourceName,
710 @Nullable String resourceType, String packageName) {
711 if (resourceName == null) {
712 return 0;
713 }
714 try {
715 try {
716 // It the name can be parsed as an integer, just use it.
717 return Integer.parseInt(resourceName);
718 } catch (NumberFormatException ignore) {
719 }
720
721 return res.getIdentifier(resourceName, resourceType, packageName);
722 } catch (NotFoundException e) {
723 Log.e(TAG, "Resource ID for name=" + resourceName + " not found in package "
724 + packageName);
725 return 0;
726 }
727 }
728
729 /**
730 * Look up resource names from the resource IDs for the icon res and the text fields, and fill
731 * in the resource name fields.
732 *
733 * @param res {@link Resources} for the publisher. Must have been loaded with
734 * {@link PackageManager#getResourcesForApplicationAsUser}.
735 *
736 * @hide
737 */
738 public void lookupAndFillInResourceNames(@NonNull Resources res) {
739 if ((mTitleResId == 0) && (mTextResId == 0) && (mDisabledMessageResId == 0)
740 && (mIconResId == 0)) {
741 return; // Bail early.
742 }
743
744 // We don't need types for strings because their types are always "string".
745 mTitleResName = lookUpResourceName(res, mTitleResId, /*withType=*/ false, mPackageName);
746 mTextResName = lookUpResourceName(res, mTextResId, /*withType=*/ false, mPackageName);
747 mDisabledMessageResName = lookUpResourceName(res, mDisabledMessageResId,
748 /*withType=*/ false, mPackageName);
749
750 // But icons have multiple possible types, so include the type.
751 mIconResName = lookUpResourceName(res, mIconResId, /*withType=*/ true, mPackageName);
752 }
753
754 /**
755 * Look up resource IDs from the resource names for the icon res and the text fields, and fill
756 * in the resource ID fields.
757 *
758 * This is called when an app is updated.
759 *
760 * @hide
761 */
762 public void lookupAndFillInResourceIds(@NonNull Resources res) {
763 if ((mTitleResName == null) && (mTextResName == null) && (mDisabledMessageResName == null)
764 && (mIconResName == null)) {
765 return; // Bail early.
766 }
767
768 mTitleResId = lookUpResourceId(res, mTitleResName, RES_TYPE_STRING, mPackageName);
769 mTextResId = lookUpResourceId(res, mTextResName, RES_TYPE_STRING, mPackageName);
770 mDisabledMessageResId = lookUpResourceId(res, mDisabledMessageResName, RES_TYPE_STRING,
771 mPackageName);
772
773 // mIconResName already contains the type, so the third argument is not needed.
774 mIconResId = lookUpResourceId(res, mIconResName, null, mPackageName);
775 }
776
777 /**
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800778 * Copy a {@link ShortcutInfo}, optionally removing fields.
779 * @hide
780 */
781 public ShortcutInfo clone(@CloneFlags int cloneFlags) {
782 return new ShortcutInfo(this, cloneFlags);
783 }
784
785 /**
Makoto Onuki22fcc682016-05-17 14:52:19 -0700786 * @hide
Makoto Onukia4f89b12017-10-05 10:37:55 -0700787 *
788 * @isUpdating set true if it's "update", as opposed to "replace".
Makoto Onuki22fcc682016-05-17 14:52:19 -0700789 */
Makoto Onukia4f89b12017-10-05 10:37:55 -0700790 public void ensureUpdatableWith(ShortcutInfo source, boolean isUpdating) {
791 if (isUpdating) {
792 Preconditions.checkState(isVisibleToPublisher(),
793 "[Framework BUG] Invisible shortcuts can't be updated");
794 }
Makoto Onuki22fcc682016-05-17 14:52:19 -0700795 Preconditions.checkState(mUserId == source.mUserId, "Owner User ID must match");
796 Preconditions.checkState(mId.equals(source.mId), "ID must match");
797 Preconditions.checkState(mPackageName.equals(source.mPackageName),
798 "Package name must match");
Makoto Onukia4f89b12017-10-05 10:37:55 -0700799
800 if (isVisibleToPublisher()) {
801 // Don't do this check for restore-blocked shortcuts.
802 Preconditions.checkState(!isImmutable(), "Target ShortcutInfo is immutable");
803 }
Makoto Onuki22fcc682016-05-17 14:52:19 -0700804 }
805
806 /**
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800807 * Copy non-null/zero fields from another {@link ShortcutInfo}. Only "public" information
Makoto Onuki9e1f5592016-06-08 12:30:23 -0700808 * will be overwritten. The timestamp will *not* be updated to be consistent with other
809 * setters (and also the clock is not injectable in this file).
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800810 *
811 * - Flags will not change
812 * - mBitmapPath will not change
813 * - Current time will be set to timestamp
814 *
Makoto Onuki22fcc682016-05-17 14:52:19 -0700815 * @throws IllegalStateException if source is not compatible.
816 *
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800817 * @hide
818 */
819 public void copyNonNullFieldsFrom(ShortcutInfo source) {
Makoto Onukia4f89b12017-10-05 10:37:55 -0700820 ensureUpdatableWith(source, /*isUpdating=*/ true);
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800821
Makoto Onuki22fcc682016-05-17 14:52:19 -0700822 if (source.mActivity != null) {
823 mActivity = source.mActivity;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800824 }
825
826 if (source.mIcon != null) {
827 mIcon = source.mIcon;
Makoto Onuki157b1622016-06-02 16:13:10 -0700828
829 mIconResId = 0;
830 mIconResName = null;
831 mBitmapPath = null;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800832 }
833 if (source.mTitle != null) {
834 mTitle = source.mTitle;
Makoto Onuki20c95f82016-05-11 16:51:01 -0700835 mTitleResId = 0;
Makoto Onuki157b1622016-06-02 16:13:10 -0700836 mTitleResName = null;
Makoto Onuki20c95f82016-05-11 16:51:01 -0700837 } else if (source.mTitleResId != 0) {
838 mTitle = null;
Makoto Onukieddbfec2016-05-31 17:04:34 -0700839 mTitleResId = source.mTitleResId;
Makoto Onuki157b1622016-06-02 16:13:10 -0700840 mTitleResName = null;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800841 }
Makoto Onuki157b1622016-06-02 16:13:10 -0700842
Makoto Onukie3ae7ec2016-03-29 15:45:25 -0700843 if (source.mText != null) {
844 mText = source.mText;
Makoto Onuki20c95f82016-05-11 16:51:01 -0700845 mTextResId = 0;
Makoto Onuki157b1622016-06-02 16:13:10 -0700846 mTextResName = null;
Makoto Onuki20c95f82016-05-11 16:51:01 -0700847 } else if (source.mTextResId != 0) {
848 mText = null;
849 mTextResId = source.mTextResId;
Makoto Onuki157b1622016-06-02 16:13:10 -0700850 mTextResName = null;
Makoto Onuki20c95f82016-05-11 16:51:01 -0700851 }
852 if (source.mDisabledMessage != null) {
853 mDisabledMessage = source.mDisabledMessage;
854 mDisabledMessageResId = 0;
Makoto Onuki157b1622016-06-02 16:13:10 -0700855 mDisabledMessageResName = null;
Makoto Onuki20c95f82016-05-11 16:51:01 -0700856 } else if (source.mDisabledMessageResId != 0) {
857 mDisabledMessage = null;
858 mDisabledMessageResId = source.mDisabledMessageResId;
Makoto Onuki157b1622016-06-02 16:13:10 -0700859 mDisabledMessageResName = null;
Makoto Onukie3ae7ec2016-03-29 15:45:25 -0700860 }
Makoto Onukib6d35232016-04-04 15:57:17 -0700861 if (source.mCategories != null) {
Makoto Onukidf6da042016-06-16 09:51:40 -0700862 mCategories = cloneCategories(source.mCategories);
Makoto Onukib6d35232016-04-04 15:57:17 -0700863 }
Mehdi Alizadeh14242af2018-12-20 20:11:35 -0800864 if (source.mPersons != null) {
865 mPersons = clonePersons(source.mPersons);
866 }
Makoto Onuki440a1ea2016-07-20 14:21:18 -0700867 if (source.mIntents != null) {
868 mIntents = cloneIntents(source.mIntents);
869 mIntentPersistableExtrases =
870 clonePersistableBundle(source.mIntentPersistableExtrases);
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800871 }
Makoto Onuki9e1f5592016-06-08 12:30:23 -0700872 if (source.mRank != RANK_NOT_SET) {
Makoto Onuki20c95f82016-05-11 16:51:01 -0700873 mRank = source.mRank;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800874 }
875 if (source.mExtras != null) {
876 mExtras = source.mExtras;
877 }
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800878 }
879
880 /**
Makoto Onuki55046222016-03-08 10:49:47 -0800881 * @hide
882 */
883 public static Icon validateIcon(Icon icon) {
884 switch (icon.getType()) {
885 case Icon.TYPE_RESOURCE:
886 case Icon.TYPE_BITMAP:
Hyunyoung Songe4179e22017-03-01 12:51:26 -0800887 case Icon.TYPE_ADAPTIVE_BITMAP:
Makoto Onuki55046222016-03-08 10:49:47 -0800888 break; // OK
Makoto Onuki55046222016-03-08 10:49:47 -0800889 default:
890 throw getInvalidIconException();
891 }
892 if (icon.hasTint()) {
Makoto Onuki55046222016-03-08 10:49:47 -0800893 throw new IllegalArgumentException("Icons with tints are not supported");
894 }
895
896 return icon;
897 }
898
899 /** @hide */
900 public static IllegalArgumentException getInvalidIconException() {
901 return new IllegalArgumentException("Unsupported icon type:"
Makoto Onukia97256b2016-07-15 13:23:54 -0700902 +" only the bitmap and resource types are supported");
Makoto Onuki55046222016-03-08 10:49:47 -0800903 }
904
905 /**
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800906 * Builder class for {@link ShortcutInfo} objects.
Makoto Onuki4a910962016-07-07 13:57:34 -0700907 *
908 * @see ShortcutManager
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800909 */
910 public static class Builder {
911 private final Context mContext;
912
913 private String mId;
914
Makoto Onuki22fcc682016-05-17 14:52:19 -0700915 private ComponentName mActivity;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800916
917 private Icon mIcon;
918
Makoto Onuki20c95f82016-05-11 16:51:01 -0700919 private int mTitleResId;
920
Makoto Onuki22fcc682016-05-17 14:52:19 -0700921 private CharSequence mTitle;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800922
Makoto Onuki20c95f82016-05-11 16:51:01 -0700923 private int mTextResId;
924
Makoto Onuki22fcc682016-05-17 14:52:19 -0700925 private CharSequence mText;
Makoto Onukie3ae7ec2016-03-29 15:45:25 -0700926
Makoto Onuki20c95f82016-05-11 16:51:01 -0700927 private int mDisabledMessageResId;
928
Makoto Onuki22fcc682016-05-17 14:52:19 -0700929 private CharSequence mDisabledMessage;
Makoto Onuki20c95f82016-05-11 16:51:01 -0700930
Makoto Onukibe73a802016-04-15 14:46:35 -0700931 private Set<String> mCategories;
Makoto Onukib6d35232016-04-04 15:57:17 -0700932
Makoto Onuki440a1ea2016-07-20 14:21:18 -0700933 private Intent[] mIntents;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800934
Mehdi Alizadeh14242af2018-12-20 20:11:35 -0800935 private Person[] mPersons;
936
937 private boolean mIsLongLived;
938
Makoto Onuki9e1f5592016-06-08 12:30:23 -0700939 private int mRank = RANK_NOT_SET;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800940
941 private PersistableBundle mExtras;
942
Makoto Onukib5a012f2016-06-21 11:13:53 -0700943 /**
Makoto Onuki598aca42016-07-06 16:05:03 -0700944 * Old style constructor.
945 * @hide
Makoto Onukib5a012f2016-06-21 11:13:53 -0700946 */
947 @Deprecated
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800948 public Builder(Context context) {
949 mContext = context;
950 }
951
952 /**
Makoto Onuki598aca42016-07-06 16:05:03 -0700953 * Used with the old style constructor, kept for unit tests.
954 * @hide
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800955 */
956 @NonNull
Makoto Onukib5a012f2016-06-21 11:13:53 -0700957 @Deprecated
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800958 public Builder setId(@NonNull String id) {
Makoto Onukib08790c2016-06-23 14:05:46 -0700959 mId = Preconditions.checkStringNotEmpty(id, "id cannot be empty");
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800960 return this;
961 }
962
963 /**
Makoto Onukib5a012f2016-06-21 11:13:53 -0700964 * Constructor.
965 *
966 * @param context Client context.
967 * @param id ID of the shortcut.
968 */
969 public Builder(Context context, String id) {
970 mContext = context;
Makoto Onukib08790c2016-06-23 14:05:46 -0700971 mId = Preconditions.checkStringNotEmpty(id, "id cannot be empty");
Makoto Onukib5a012f2016-06-21 11:13:53 -0700972 }
973
974 /**
Makoto Onuki4a910962016-07-07 13:57:34 -0700975 * Sets the target activity. A shortcut will be shown along with this activity's icon
976 * on the launcher.
Makoto Onukib5a012f2016-06-21 11:13:53 -0700977 *
Makoto Onukife9c9662016-07-25 15:12:23 -0700978 * When selecting a target activity, keep the following in mind:
Makoto Onuki4a910962016-07-07 13:57:34 -0700979 * <ul>
Makoto Onukife9c9662016-07-25 15:12:23 -0700980 * <li>All dynamic shortcuts must have a target activity. When a shortcut with no target
981 * activity is published using
982 * {@link ShortcutManager#addDynamicShortcuts(List)} or
983 * {@link ShortcutManager#setDynamicShortcuts(List)},
Kevin Hufnagle68d699d2016-10-14 19:04:51 -0700984 * the first main activity defined in the app's <code>AndroidManifest.xml</code>
Makoto Onukife9c9662016-07-25 15:12:23 -0700985 * file is used.
986 *
987 * <li>Only "main" activities&mdash;ones that define the {@link Intent#ACTION_MAIN}
988 * and {@link Intent#CATEGORY_LAUNCHER} intent filters&mdash;can be target
Makoto Onuki4a910962016-07-07 13:57:34 -0700989 * activities.
990 *
Kevin Hufnagle68d699d2016-10-14 19:04:51 -0700991 * <li>By default, the first main activity defined in the app's manifest is
Makoto Onukife9c9662016-07-25 15:12:23 -0700992 * the target activity.
Makoto Onuki4d36b3a2016-04-27 12:00:17 -0700993 *
Kevin Hufnagle68d699d2016-10-14 19:04:51 -0700994 * <li>A target activity must belong to the publisher app.
Makoto Onuki4a910962016-07-07 13:57:34 -0700995 * </ul>
Makoto Onuki4d36b3a2016-04-27 12:00:17 -0700996 *
Makoto Onuki4a910962016-07-07 13:57:34 -0700997 * @see ShortcutInfo#getActivity()
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800998 */
999 @NonNull
Makoto Onuki22fcc682016-05-17 14:52:19 -07001000 public Builder setActivity(@NonNull ComponentName activity) {
Makoto Onukib08790c2016-06-23 14:05:46 -07001001 mActivity = Preconditions.checkNotNull(activity, "activity cannot be null");
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001002 return this;
1003 }
1004
1005 /**
Makoto Onuki4a910962016-07-07 13:57:34 -07001006 * Sets an icon of a shortcut.
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001007 *
Makoto Onuki4a910962016-07-07 13:57:34 -07001008 * <p>Icons are not available on {@link ShortcutInfo} instances
1009 * returned by {@link ShortcutManager} or {@link LauncherApps}. The default launcher
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001010 * app can use {@link LauncherApps#getShortcutIconDrawable(ShortcutInfo, int)}
Makoto Onukib5a012f2016-06-21 11:13:53 -07001011 * or {@link LauncherApps#getShortcutBadgedIconDrawable(ShortcutInfo, int)} to fetch
1012 * shortcut icons.
Makoto Onuki4a910962016-07-07 13:57:34 -07001013 *
1014 * <p>Tints set with {@link Icon#setTint} or {@link Icon#setTintList} are not supported
1015 * and will be ignored.
1016 *
Hyunyoung Songf281e7a2017-02-13 10:57:42 -08001017 * <p>Only icons created with {@link Icon#createWithBitmap(Bitmap)},
Hyunyoung Songe4179e22017-03-01 12:51:26 -08001018 * {@link Icon#createWithAdaptiveBitmap(Bitmap)}
Hyunyoung Songf281e7a2017-02-13 10:57:42 -08001019 * and {@link Icon#createWithResource} are supported.
Makoto Onukife9c9662016-07-25 15:12:23 -07001020 * Other types, such as URI-based icons, are not supported.
Makoto Onuki4a910962016-07-07 13:57:34 -07001021 *
1022 * @see LauncherApps#getShortcutIconDrawable(ShortcutInfo, int)
1023 * @see LauncherApps#getShortcutBadgedIconDrawable(ShortcutInfo, int)
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001024 */
1025 @NonNull
1026 public Builder setIcon(Icon icon) {
Makoto Onuki55046222016-03-08 10:49:47 -08001027 mIcon = validateIcon(icon);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001028 return this;
1029 }
1030
Makoto Onukieddbfec2016-05-31 17:04:34 -07001031 /**
1032 * @hide We don't support resource strings for dynamic shortcuts for now. (But unit tests
1033 * use it.)
1034 */
Makoto Onukib5a012f2016-06-21 11:13:53 -07001035 @Deprecated
Makoto Onukieddbfec2016-05-31 17:04:34 -07001036 public Builder setShortLabelResId(int shortLabelResId) {
1037 Preconditions.checkState(mTitle == null, "shortLabel already set");
1038 mTitleResId = shortLabelResId;
Makoto Onuki20c95f82016-05-11 16:51:01 -07001039 return this;
1040 }
1041
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001042 /**
Makoto Onukib5a012f2016-06-21 11:13:53 -07001043 * Sets the short title of a shortcut.
1044 *
Makoto Onuki4a910962016-07-07 13:57:34 -07001045 * <p>This is a mandatory field when publishing a new shortcut with
1046 * {@link ShortcutManager#addDynamicShortcuts(List)} or
1047 * {@link ShortcutManager#setDynamicShortcuts(List)}.
Makoto Onuki0e65d362016-03-29 14:46:50 -07001048 *
Makoto Onukife9c9662016-07-25 15:12:23 -07001049 * <p>This field is intended to be a concise description of a shortcut.
Makoto Onuki4a910962016-07-07 13:57:34 -07001050 *
Makoto Onukife9c9662016-07-25 15:12:23 -07001051 * <p>The recommended maximum length is 10 characters.
Makoto Onuki4a910962016-07-07 13:57:34 -07001052 *
1053 * @see ShortcutInfo#getShortLabel()
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001054 */
1055 @NonNull
Makoto Onukidf6da042016-06-16 09:51:40 -07001056 public Builder setShortLabel(@NonNull CharSequence shortLabel) {
Makoto Onukieddbfec2016-05-31 17:04:34 -07001057 Preconditions.checkState(mTitleResId == 0, "shortLabelResId already set");
Makoto Onukib08790c2016-06-23 14:05:46 -07001058 mTitle = Preconditions.checkStringNotEmpty(shortLabel, "shortLabel cannot be empty");
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001059 return this;
1060 }
1061
Makoto Onukieddbfec2016-05-31 17:04:34 -07001062 /**
1063 * @hide We don't support resource strings for dynamic shortcuts for now. (But unit tests
1064 * use it.)
1065 */
Makoto Onukib5a012f2016-06-21 11:13:53 -07001066 @Deprecated
Makoto Onukieddbfec2016-05-31 17:04:34 -07001067 public Builder setLongLabelResId(int longLabelResId) {
1068 Preconditions.checkState(mText == null, "longLabel already set");
1069 mTextResId = longLabelResId;
Makoto Onuki20c95f82016-05-11 16:51:01 -07001070 return this;
1071 }
1072
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001073 /**
Makoto Onukib5a012f2016-06-21 11:13:53 -07001074 * Sets the text of a shortcut.
Makoto Onuki0e65d362016-03-29 14:46:50 -07001075 *
Makoto Onukieddbfec2016-05-31 17:04:34 -07001076 * <p>This field is intended to be more descriptive than the shortcut title. The launcher
Makoto Onuki4a910962016-07-07 13:57:34 -07001077 * shows this instead of the short title when it has enough space.
1078 *
Makoto Onukife9c9662016-07-25 15:12:23 -07001079 * <p>The recommend maximum length is 25 characters.
Makoto Onuki4a910962016-07-07 13:57:34 -07001080 *
1081 * @see ShortcutInfo#getLongLabel()
Makoto Onukie3ae7ec2016-03-29 15:45:25 -07001082 */
1083 @NonNull
Makoto Onukidf6da042016-06-16 09:51:40 -07001084 public Builder setLongLabel(@NonNull CharSequence longLabel) {
Makoto Onukieddbfec2016-05-31 17:04:34 -07001085 Preconditions.checkState(mTextResId == 0, "longLabelResId already set");
Makoto Onukib08790c2016-06-23 14:05:46 -07001086 mText = Preconditions.checkStringNotEmpty(longLabel, "longLabel cannot be empty");
Makoto Onukie3ae7ec2016-03-29 15:45:25 -07001087 return this;
1088 }
1089
Makoto Onukieddbfec2016-05-31 17:04:34 -07001090 /** @hide -- old signature, the internal code still uses it. */
Makoto Onukib5a012f2016-06-21 11:13:53 -07001091 @Deprecated
Makoto Onukidf6da042016-06-16 09:51:40 -07001092 public Builder setTitle(@NonNull CharSequence value) {
Makoto Onukieddbfec2016-05-31 17:04:34 -07001093 return setShortLabel(value);
1094 }
1095
1096 /** @hide -- old signature, the internal code still uses it. */
Makoto Onukib5a012f2016-06-21 11:13:53 -07001097 @Deprecated
Makoto Onukieddbfec2016-05-31 17:04:34 -07001098 public Builder setTitleResId(int value) {
1099 return setShortLabelResId(value);
1100 }
1101
1102 /** @hide -- old signature, the internal code still uses it. */
Makoto Onukib5a012f2016-06-21 11:13:53 -07001103 @Deprecated
Makoto Onukidf6da042016-06-16 09:51:40 -07001104 public Builder setText(@NonNull CharSequence value) {
Makoto Onukieddbfec2016-05-31 17:04:34 -07001105 return setLongLabel(value);
1106 }
1107
1108 /** @hide -- old signature, the internal code still uses it. */
Makoto Onukib5a012f2016-06-21 11:13:53 -07001109 @Deprecated
Makoto Onukieddbfec2016-05-31 17:04:34 -07001110 public Builder setTextResId(int value) {
1111 return setLongLabelResId(value);
1112 }
1113
1114 /**
1115 * @hide We don't support resource strings for dynamic shortcuts for now. (But unit tests
1116 * use it.)
1117 */
Makoto Onukib5a012f2016-06-21 11:13:53 -07001118 @Deprecated
Makoto Onuki20c95f82016-05-11 16:51:01 -07001119 public Builder setDisabledMessageResId(int disabledMessageResId) {
1120 Preconditions.checkState(mDisabledMessage == null, "disabledMessage already set");
1121 mDisabledMessageResId = disabledMessageResId;
1122 return this;
1123 }
1124
Makoto Onuki4a910962016-07-07 13:57:34 -07001125 /**
Makoto Onukife9c9662016-07-25 15:12:23 -07001126 * Sets the message that should be shown when the user attempts to start a shortcut that
1127 * is disabled.
Makoto Onuki4a910962016-07-07 13:57:34 -07001128 *
1129 * @see ShortcutInfo#getDisabledMessage()
1130 */
Makoto Onuki20c95f82016-05-11 16:51:01 -07001131 @NonNull
Makoto Onukidf6da042016-06-16 09:51:40 -07001132 public Builder setDisabledMessage(@NonNull CharSequence disabledMessage) {
Makoto Onuki20c95f82016-05-11 16:51:01 -07001133 Preconditions.checkState(
1134 mDisabledMessageResId == 0, "disabledMessageResId already set");
1135 mDisabledMessage =
Makoto Onukib08790c2016-06-23 14:05:46 -07001136 Preconditions.checkStringNotEmpty(disabledMessage,
1137 "disabledMessage cannot be empty");
Makoto Onuki20c95f82016-05-11 16:51:01 -07001138 return this;
1139 }
1140
Makoto Onukie3ae7ec2016-03-29 15:45:25 -07001141 /**
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001142 * Sets categories for a shortcut. Launcher apps may use this information to
1143 * categorize shortcuts.
Makoto Onukib6d35232016-04-04 15:57:17 -07001144 *
1145 * @see #SHORTCUT_CATEGORY_CONVERSATION
Makoto Onuki4a910962016-07-07 13:57:34 -07001146 * @see ShortcutInfo#getCategories()
Makoto Onukib6d35232016-04-04 15:57:17 -07001147 */
1148 @NonNull
Makoto Onukibe73a802016-04-15 14:46:35 -07001149 public Builder setCategories(Set<String> categories) {
Makoto Onukib6d35232016-04-04 15:57:17 -07001150 mCategories = categories;
1151 return this;
1152 }
1153
1154 /**
Makoto Onuki0eed4412016-07-21 11:21:59 -07001155 * Sets the intent of a shortcut. Alternatively, {@link #setIntents(Intent[])} can be used
1156 * to launch an activity with other activities in the back stack.
Makoto Onuki4a910962016-07-07 13:57:34 -07001157 *
1158 * <p>This is a mandatory field when publishing a new shortcut with
1159 * {@link ShortcutManager#addDynamicShortcuts(List)} or
1160 * {@link ShortcutManager#setDynamicShortcuts(List)}.
1161 *
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001162 * <p>A shortcut can launch any intent that the publisher app has permission to
Makoto Onukife9c9662016-07-25 15:12:23 -07001163 * launch. For example, a shortcut can launch an unexported activity within the publisher
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001164 * app. A shortcut intent doesn't have to point at the target activity.
Makoto Onuki4a910962016-07-07 13:57:34 -07001165 *
Makoto Onukife9c9662016-07-25 15:12:23 -07001166 * <p>The given {@code intent} can contain extras, but these extras must contain values
1167 * of primitive types in order for the system to persist these values.
Makoto Onuki4a910962016-07-07 13:57:34 -07001168 *
1169 * @see ShortcutInfo#getIntent()
Makoto Onuki440a1ea2016-07-20 14:21:18 -07001170 * @see #setIntents(Intent[])
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001171 */
1172 @NonNull
1173 public Builder setIntent(@NonNull Intent intent) {
Makoto Onuki440a1ea2016-07-20 14:21:18 -07001174 return setIntents(new Intent[]{intent});
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001175 }
1176
1177 /**
Makoto Onuki0eed4412016-07-21 11:21:59 -07001178 * Sets multiple intents instead of a single intent, in order to launch an activity with
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001179 * other activities in back stack. Use {@link TaskStackBuilder} to build intents. The
1180 * last element in the list represents the only intent that doesn't place an activity on
1181 * the back stack.
Makoto Onuki0eed4412016-07-21 11:21:59 -07001182 * See the {@link ShortcutManager} javadoc for details.
Makoto Onuki347a6bd2016-07-19 11:13:08 -07001183 *
1184 * @see Builder#setIntent(Intent)
1185 * @see ShortcutInfo#getIntents()
1186 * @see Context#startActivities(Intent[])
1187 * @see TaskStackBuilder
1188 */
1189 @NonNull
1190 public Builder setIntents(@NonNull Intent[] intents) {
Makoto Onuki440a1ea2016-07-20 14:21:18 -07001191 Preconditions.checkNotNull(intents, "intents cannot be null");
1192 Preconditions.checkNotNull(intents.length, "intents cannot be empty");
1193 for (Intent intent : intents) {
1194 Preconditions.checkNotNull(intent, "intents cannot contain null");
1195 Preconditions.checkNotNull(intent.getAction(), "intent's action must be set");
1196 }
1197 // Make sure always clone incoming intents.
1198 mIntents = cloneIntents(intents);
1199 return this;
Makoto Onuki347a6bd2016-07-19 11:13:08 -07001200 }
1201
1202 /**
Mehdi Alizadeh14242af2018-12-20 20:11:35 -08001203 * Add a person that is relevant to this shortcut. Alternatively,
1204 * {@link #setPersons(Person[])} can be used to add multiple persons to a shortcut.
1205 *
1206 * <p> This is an optional field, but the addition of person may cause this shortcut to
1207 * appear more prominently in the user interface (e.g. ShareSheet).
1208 *
1209 * <p> A person should usually contain a uri in order to benefit from the ranking boost.
1210 * However, even if no uri is provided, it's beneficial to provide people in the shortcut,
1211 * such that listeners and voice only devices can announce and handle them properly.
1212 *
1213 * @see Person
1214 * @see #setPersons(Person[])
1215 */
1216 @NonNull
1217 public Builder setPerson(@NonNull Person person) {
1218 return setPersons(new Person[]{person});
1219 }
1220
1221 /**
1222 * Sets multiple persons instead of a single person.
1223 *
1224 * @see Person
1225 * @see #setPerson(Person)
1226 */
1227 @NonNull
1228 public Builder setPersons(@NonNull Person[] persons) {
1229 Preconditions.checkNotNull(persons, "persons cannot be null");
1230 Preconditions.checkNotNull(persons.length, "persons cannot be empty");
1231 for (Person person : persons) {
1232 Preconditions.checkNotNull(person, "persons cannot contain null");
1233 }
1234 mPersons = clonePersons(persons);
1235 return this;
1236 }
1237
1238 /**
1239 * Sets if a shortcut would be valid even if it has been unpublished/invisible by the app
1240 * (as a dynamic or pinned shortcut). If it is long lived, it can be cached by various
1241 * system services even after it has been unpublished as a dynamic shortcut.
1242 */
1243 @NonNull
1244 public Builder setLongLived() {
1245 mIsLongLived = true;
1246 return this;
1247 }
1248
1249 /**
Makoto Onuki9e1f5592016-06-08 12:30:23 -07001250 * "Rank" of a shortcut, which is a non-negative value that's used by the launcher app
1251 * to sort shortcuts.
Makoto Onuki4a910962016-07-07 13:57:34 -07001252 *
1253 * See {@link ShortcutInfo#getRank()} for details.
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001254 */
1255 @NonNull
Makoto Onuki20c95f82016-05-11 16:51:01 -07001256 public Builder setRank(int rank) {
Makoto Onuki9e1f5592016-06-08 12:30:23 -07001257 Preconditions.checkArgument((0 <= rank),
1258 "Rank cannot be negative or bigger than MAX_RANK");
Makoto Onuki20c95f82016-05-11 16:51:01 -07001259 mRank = rank;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001260 return this;
1261 }
1262
1263 /**
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001264 * Extras that the app can set for any purpose.
Makoto Onukib5a012f2016-06-21 11:13:53 -07001265 *
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001266 * <p>Apps can store arbitrary shortcut metadata in extras and retrieve the
Makoto Onukife9c9662016-07-25 15:12:23 -07001267 * metadata later using {@link ShortcutInfo#getExtras()}.
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001268 */
1269 @NonNull
1270 public Builder setExtras(@NonNull PersistableBundle extras) {
1271 mExtras = extras;
1272 return this;
1273 }
1274
Hakan Seyalioglu58fc95d2016-12-13 15:23:22 -08001275 /**
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001276 * Creates a {@link ShortcutInfo} instance.
1277 */
1278 @NonNull
1279 public ShortcutInfo build() {
1280 return new ShortcutInfo(this);
1281 }
1282 }
1283
1284 /**
Makoto Onuki4a910962016-07-07 13:57:34 -07001285 * Returns the ID of a shortcut.
1286 *
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001287 * <p>Shortcut IDs are unique within each publisher app and must be stable across
Makoto Onukife9c9662016-07-25 15:12:23 -07001288 * devices so that shortcuts will still be valid when restored on a different device.
1289 * See {@link ShortcutManager} for details.
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001290 */
1291 @NonNull
1292 public String getId() {
1293 return mId;
1294 }
1295
1296 /**
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001297 * Return the package name of the publisher app.
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001298 */
1299 @NonNull
Makoto Onuki22fcc682016-05-17 14:52:19 -07001300 public String getPackage() {
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001301 return mPackageName;
1302 }
1303
1304 /**
Makoto Onuki4a910962016-07-07 13:57:34 -07001305 * Return the target activity.
Makoto Onuki4d36b3a2016-04-27 12:00:17 -07001306 *
Makoto Onukife9c9662016-07-25 15:12:23 -07001307 * <p>This has nothing to do with the activity that this shortcut will launch.
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001308 * Launcher apps should show the launcher icon for the returned activity alongside
Makoto Onukife9c9662016-07-25 15:12:23 -07001309 * this shortcut.
Makoto Onuki4d36b3a2016-04-27 12:00:17 -07001310 *
Makoto Onuki22fcc682016-05-17 14:52:19 -07001311 * @see Builder#setActivity
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001312 */
1313 @Nullable
Makoto Onuki22fcc682016-05-17 14:52:19 -07001314 public ComponentName getActivity() {
1315 return mActivity;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001316 }
1317
Makoto Onukib08790c2016-06-23 14:05:46 -07001318 /** @hide */
1319 public void setActivity(ComponentName activity) {
1320 mActivity = activity;
1321 }
1322
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001323 /**
Makoto Onuki4a910962016-07-07 13:57:34 -07001324 * Returns the shortcut icon.
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001325 *
1326 * @hide
1327 */
1328 @Nullable
Mathew Inwood8c854f82018-09-14 12:35:36 +01001329 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001330 public Icon getIcon() {
1331 return mIcon;
1332 }
1333
Makoto Onukieddbfec2016-05-31 17:04:34 -07001334 /** @hide -- old signature, the internal code still uses it. */
Makoto Onuki55046222016-03-08 10:49:47 -08001335 @Nullable
Makoto Onukib5a012f2016-06-21 11:13:53 -07001336 @Deprecated
Makoto Onuki22fcc682016-05-17 14:52:19 -07001337 public CharSequence getTitle() {
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001338 return mTitle;
1339 }
1340
Makoto Onukieddbfec2016-05-31 17:04:34 -07001341 /** @hide -- old signature, the internal code still uses it. */
Makoto Onukib5a012f2016-06-21 11:13:53 -07001342 @Deprecated
Makoto Onuki20c95f82016-05-11 16:51:01 -07001343 public int getTitleResId() {
1344 return mTitleResId;
1345 }
1346
Makoto Onukieddbfec2016-05-31 17:04:34 -07001347 /** @hide -- old signature, the internal code still uses it. */
1348 @Nullable
Makoto Onukib5a012f2016-06-21 11:13:53 -07001349 @Deprecated
Makoto Onukieddbfec2016-05-31 17:04:34 -07001350 public CharSequence getText() {
1351 return mText;
1352 }
1353
1354 /** @hide -- old signature, the internal code still uses it. */
Makoto Onukib5a012f2016-06-21 11:13:53 -07001355 @Deprecated
Makoto Onukieddbfec2016-05-31 17:04:34 -07001356 public int getTextResId() {
1357 return mTextResId;
1358 }
1359
1360 /**
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001361 * Return the short description of a shortcut.
Makoto Onukieddbfec2016-05-31 17:04:34 -07001362 *
Makoto Onuki4a910962016-07-07 13:57:34 -07001363 * @see Builder#setShortLabel(CharSequence)
Makoto Onukieddbfec2016-05-31 17:04:34 -07001364 */
1365 @Nullable
1366 public CharSequence getShortLabel() {
1367 return mTitle;
1368 }
1369
Makoto Onuki598aca42016-07-06 16:05:03 -07001370 /** @hide */
Makoto Onukieddbfec2016-05-31 17:04:34 -07001371 public int getShortLabelResourceId() {
1372 return mTitleResId;
1373 }
1374
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001375 /**
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001376 * Return the long description of a shortcut.
Makoto Onuki4a910962016-07-07 13:57:34 -07001377 *
1378 * @see Builder#setLongLabel(CharSequence)
Makoto Onukie3ae7ec2016-03-29 15:45:25 -07001379 */
1380 @Nullable
Makoto Onukieddbfec2016-05-31 17:04:34 -07001381 public CharSequence getLongLabel() {
Makoto Onukie3ae7ec2016-03-29 15:45:25 -07001382 return mText;
1383 }
1384
Makoto Onuki598aca42016-07-06 16:05:03 -07001385 /** @hide */
Makoto Onukieddbfec2016-05-31 17:04:34 -07001386 public int getLongLabelResourceId() {
Makoto Onuki20c95f82016-05-11 16:51:01 -07001387 return mTextResId;
1388 }
1389
1390 /**
Makoto Onukife9c9662016-07-25 15:12:23 -07001391 * Return the message that should be shown when the user attempts to start a shortcut
1392 * that is disabled.
Makoto Onuki4a910962016-07-07 13:57:34 -07001393 *
1394 * @see Builder#setDisabledMessage(CharSequence)
Makoto Onuki20c95f82016-05-11 16:51:01 -07001395 */
1396 @Nullable
Makoto Onuki22fcc682016-05-17 14:52:19 -07001397 public CharSequence getDisabledMessage() {
Makoto Onuki20c95f82016-05-11 16:51:01 -07001398 return mDisabledMessage;
1399 }
1400
Makoto Onuki598aca42016-07-06 16:05:03 -07001401 /** @hide */
Makoto Onukieddbfec2016-05-31 17:04:34 -07001402 public int getDisabledMessageResourceId() {
Makoto Onuki20c95f82016-05-11 16:51:01 -07001403 return mDisabledMessageResId;
1404 }
1405
Makoto Onukia4f89b12017-10-05 10:37:55 -07001406 /** @hide */
1407 public void setDisabledReason(@DisabledReason int reason) {
1408 mDisabledReason = reason;
1409 }
1410
1411 /**
1412 * Returns why a shortcut has been disabled.
1413 */
1414 @DisabledReason
1415 public int getDisabledReason() {
1416 return mDisabledReason;
1417 }
1418
Makoto Onukie3ae7ec2016-03-29 15:45:25 -07001419 /**
Makoto Onukife9c9662016-07-25 15:12:23 -07001420 * Return the shortcut's categories.
Makoto Onuki4a910962016-07-07 13:57:34 -07001421 *
1422 * @see Builder#setCategories(Set)
Makoto Onukib6d35232016-04-04 15:57:17 -07001423 */
1424 @Nullable
Makoto Onukibe73a802016-04-15 14:46:35 -07001425 public Set<String> getCategories() {
Makoto Onukib6d35232016-04-04 15:57:17 -07001426 return mCategories;
1427 }
1428
1429 /**
Makoto Onukife9c9662016-07-25 15:12:23 -07001430 * Returns the intent that is executed when the user selects this shortcut.
1431 * If setIntents() was used, then return the last intent in the array.
Makoto Onuki55046222016-03-08 10:49:47 -08001432 *
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001433 * <p>Launcher apps <b>cannot</b> see the intent. If a {@link ShortcutInfo} is
Makoto Onuki4a910962016-07-07 13:57:34 -07001434 * obtained via {@link LauncherApps}, then this method will always return null.
1435 * Launchers can only start a shortcut intent with {@link LauncherApps#startShortcut}.
Makoto Onuki4d36b3a2016-04-27 12:00:17 -07001436 *
Makoto Onuki4a910962016-07-07 13:57:34 -07001437 * @see Builder#setIntent(Intent)
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001438 */
Makoto Onuki55046222016-03-08 10:49:47 -08001439 @Nullable
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001440 public Intent getIntent() {
Makoto Onuki440a1ea2016-07-20 14:21:18 -07001441 if (mIntents == null || mIntents.length == 0) {
Makoto Onuki55046222016-03-08 10:49:47 -08001442 return null;
1443 }
Makoto Onuki440a1ea2016-07-20 14:21:18 -07001444 final int last = mIntents.length - 1;
1445 final Intent intent = new Intent(mIntents[last]);
1446 return setIntentExtras(intent, mIntentPersistableExtrases[last]);
Makoto Onuki55046222016-03-08 10:49:47 -08001447 }
1448
1449 /**
Makoto Onuki347a6bd2016-07-19 11:13:08 -07001450 * Return the intent set with {@link Builder#setIntents(Intent[])}.
1451 *
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001452 * <p>Launcher apps <b>cannot</b> see the intents. If a {@link ShortcutInfo} is
Makoto Onuki347a6bd2016-07-19 11:13:08 -07001453 * obtained via {@link LauncherApps}, then this method will always return null.
1454 * Launchers can only start a shortcut intent with {@link LauncherApps#startShortcut}.
1455 *
1456 * @see Builder#setIntents(Intent[])
1457 */
1458 @Nullable
Makoto Onuki440a1ea2016-07-20 14:21:18 -07001459 public Intent[] getIntents() {
1460 final Intent[] ret = new Intent[mIntents.length];
1461
1462 for (int i = 0; i < ret.length; i++) {
1463 ret[i] = new Intent(mIntents[i]);
1464 setIntentExtras(ret[i], mIntentPersistableExtrases[i]);
1465 }
1466
1467 return ret;
Makoto Onuki347a6bd2016-07-19 11:13:08 -07001468 }
1469
1470 /**
Makoto Onuki440a1ea2016-07-20 14:21:18 -07001471 * Return "raw" intents, which is the original intents without the extras.
Makoto Onuki55046222016-03-08 10:49:47 -08001472 * @hide
1473 */
1474 @Nullable
Makoto Onuki440a1ea2016-07-20 14:21:18 -07001475 public Intent[] getIntentsNoExtras() {
1476 return mIntents;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001477 }
1478
Makoto Onuki55046222016-03-08 10:49:47 -08001479 /**
Mehdi Alizadeh14242af2018-12-20 20:11:35 -08001480 * Return the Persons set with {@link Builder#setPersons(Person[])}.
1481 *
1482 * @hide
1483 */
1484 @Nullable
1485 public Person[] getPersons() {
1486 return clonePersons(mPersons);
1487 }
1488
1489 /**
Makoto Onuki440a1ea2016-07-20 14:21:18 -07001490 * The extras in the intents. We convert extras into {@link PersistableBundle} so we can
Makoto Onuki55046222016-03-08 10:49:47 -08001491 * persist them.
1492 * @hide
1493 */
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001494 @Nullable
Makoto Onuki440a1ea2016-07-20 14:21:18 -07001495 public PersistableBundle[] getIntentPersistableExtrases() {
1496 return mIntentPersistableExtrases;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001497 }
1498
Hakan Seyalioglu58fc95d2016-12-13 15:23:22 -08001499 /**
Makoto Onuki9e1f5592016-06-08 12:30:23 -07001500 * "Rank" of a shortcut, which is a non-negative, sequential value that's unique for each
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001501 * {@link #getActivity} for each of the two types of shortcuts (static and dynamic).
Makoto Onuki9e1f5592016-06-08 12:30:23 -07001502 *
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001503 * <p>Because static shortcuts and dynamic shortcuts have overlapping ranks,
1504 * when a launcher app shows shortcuts for an activity, it should first show
1505 * the static shortcuts, followed by the dynamic shortcuts. Within each of those categories,
Makoto Onuki9e1f5592016-06-08 12:30:23 -07001506 * shortcuts should be sorted by rank in ascending order.
1507 *
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001508 * <p><em>Floating shortcuts</em>, or shortcuts that are neither static nor dynamic, will all
1509 * have rank 0, because they aren't sorted.
Makoto Onuki4a910962016-07-07 13:57:34 -07001510 *
1511 * See the {@link ShortcutManager}'s class javadoc for details.
1512 *
1513 * @see Builder#setRank(int)
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001514 */
Makoto Onuki20c95f82016-05-11 16:51:01 -07001515 public int getRank() {
1516 return mRank;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001517 }
1518
Makoto Onuki9e1f5592016-06-08 12:30:23 -07001519 /** @hide */
1520 public boolean hasRank() {
1521 return mRank != RANK_NOT_SET;
1522 }
1523
1524 /** @hide */
1525 public void setRank(int rank) {
1526 mRank = rank;
1527 }
1528
1529 /** @hide */
1530 public void clearImplicitRankAndRankChangedFlag() {
1531 mImplicitRank = 0;
1532 }
1533
1534 /** @hide */
1535 public void setImplicitRank(int rank) {
1536 // Make sure to keep RANK_CHANGED_BIT.
1537 mImplicitRank = (mImplicitRank & RANK_CHANGED_BIT) | (rank & IMPLICIT_RANK_MASK);
1538 }
1539
1540 /** @hide */
1541 public int getImplicitRank() {
1542 return mImplicitRank & IMPLICIT_RANK_MASK;
1543 }
1544
1545 /** @hide */
1546 public void setRankChanged() {
1547 mImplicitRank |= RANK_CHANGED_BIT;
1548 }
1549
1550 /** @hide */
1551 public boolean isRankChanged() {
1552 return (mImplicitRank & RANK_CHANGED_BIT) != 0;
1553 }
1554
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001555 /**
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001556 * Extras that the app can set for any purpose.
Makoto Onuki4a910962016-07-07 13:57:34 -07001557 *
1558 * @see Builder#setExtras(PersistableBundle)
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001559 */
1560 @Nullable
1561 public PersistableBundle getExtras() {
1562 return mExtras;
1563 }
1564
Makoto Onukiabe84422016-04-07 09:41:19 -07001565 /** @hide */
1566 public int getUserId() {
1567 return mUserId;
1568 }
1569
1570 /**
Makoto Onukife9c9662016-07-25 15:12:23 -07001571 * {@link UserHandle} on which the publisher created this shortcut.
Makoto Onukiabe84422016-04-07 09:41:19 -07001572 */
1573 public UserHandle getUserHandle() {
1574 return UserHandle.of(mUserId);
1575 }
1576
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001577 /**
1578 * Last time when any of the fields was updated.
1579 */
1580 public long getLastChangedTimestamp() {
1581 return mLastChangedTimestamp;
1582 }
1583
1584 /** @hide */
1585 @ShortcutFlags
1586 public int getFlags() {
1587 return mFlags;
1588 }
1589
1590 /** @hide*/
Makoto Onukide667372016-03-15 14:29:20 -07001591 public void replaceFlags(@ShortcutFlags int flags) {
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001592 mFlags = flags;
1593 }
1594
1595 /** @hide*/
1596 public void addFlags(@ShortcutFlags int flags) {
1597 mFlags |= flags;
1598 }
1599
1600 /** @hide*/
1601 public void clearFlags(@ShortcutFlags int flags) {
1602 mFlags &= ~flags;
1603 }
1604
1605 /** @hide*/
1606 public boolean hasFlags(@ShortcutFlags int flags) {
1607 return (mFlags & flags) == flags;
1608 }
1609
Makoto Onukibf563b62017-05-04 10:25:30 -07001610 /** @hide */
1611 public boolean isReturnedByServer() {
1612 return hasFlags(FLAG_RETURNED_BY_SERVICE);
1613 }
1614
1615 /** @hide */
1616 public void setReturnedByServer() {
1617 addFlags(FLAG_RETURNED_BY_SERVICE);
1618 }
1619
Mehdi Alizadeh14242af2018-12-20 20:11:35 -08001620 /** @hide */
1621 public boolean isLongLived() {
1622 return hasFlags(FLAG_LONG_LIVED);
1623 }
1624
1625 /** @hide */
1626 public void setLongLived() {
1627 addFlags(FLAG_LONG_LIVED);
1628 }
1629
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001630 /** Return whether a shortcut is dynamic. */
1631 public boolean isDynamic() {
1632 return hasFlags(FLAG_DYNAMIC);
1633 }
1634
1635 /** Return whether a shortcut is pinned. */
1636 public boolean isPinned() {
1637 return hasFlags(FLAG_PINNED);
1638 }
1639
1640 /**
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001641 * Return whether a shortcut is static; that is, whether a shortcut is
1642 * published from AndroidManifest.xml. If {@code true}, the shortcut is
1643 * also {@link #isImmutable()}.
Makoto Onuki22fcc682016-05-17 14:52:19 -07001644 *
1645 * <p>When an app is upgraded and a shortcut is no longer published from AndroidManifest.xml,
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001646 * this will be set to {@code false}. If the shortcut is not pinned, then it'll disappear.
1647 * However, if it's pinned, it will still be visible, {@link #isEnabled()} will be
Makoto Onuki22fcc682016-05-17 14:52:19 -07001648 * {@code false} and {@link #isImmutable()} will be {@code true}.
Makoto Onuki20c95f82016-05-11 16:51:01 -07001649 */
Makoto Onukib5a012f2016-06-21 11:13:53 -07001650 public boolean isDeclaredInManifest() {
Makoto Onuki22fcc682016-05-17 14:52:19 -07001651 return hasFlags(FLAG_MANIFEST);
Makoto Onuki20c95f82016-05-11 16:51:01 -07001652 }
1653
Makoto Onukib5a012f2016-06-21 11:13:53 -07001654 /** @hide kept for unit tests */
1655 @Deprecated
1656 public boolean isManifestShortcut() {
1657 return isDeclaredInManifest();
1658 }
1659
Makoto Onuki22fcc682016-05-17 14:52:19 -07001660 /**
Makoto Onuki9fd90192017-01-06 18:31:03 +00001661 * @return true if pinned but neither static nor dynamic.
Makoto Onuki22fcc682016-05-17 14:52:19 -07001662 * @hide
1663 */
1664 public boolean isFloating() {
1665 return isPinned() && !(isDynamic() || isManifestShortcut());
1666 }
1667
1668 /** @hide */
1669 public boolean isOriginallyFromManifest() {
1670 return hasFlags(FLAG_IMMUTABLE);
1671 }
1672
Makoto Onukia4f89b12017-10-05 10:37:55 -07001673 /** @hide */
1674 public boolean isDynamicVisible() {
1675 return isDynamic() && isVisibleToPublisher();
1676 }
1677
1678 /** @hide */
1679 public boolean isPinnedVisible() {
1680 return isPinned() && isVisibleToPublisher();
1681 }
1682
1683 /** @hide */
1684 public boolean isManifestVisible() {
1685 return isDeclaredInManifest() && isVisibleToPublisher();
1686 }
1687
Makoto Onuki22fcc682016-05-17 14:52:19 -07001688 /**
1689 * Return if a shortcut is immutable, in which case it cannot be modified with any of
1690 * {@link ShortcutManager} APIs.
1691 *
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001692 * <p>All static shortcuts are immutable. When a static shortcut is pinned and is then
1693 * disabled because it doesn't appear in AndroidManifest.xml for a newer version of the
1694 * app, {@link #isDeclaredInManifest()} returns {@code false}, but the shortcut
1695 * is still immutable.
Makoto Onuki22fcc682016-05-17 14:52:19 -07001696 *
1697 * <p>All shortcuts originally published via the {@link ShortcutManager} APIs
1698 * are all mutable.
1699 */
1700 public boolean isImmutable() {
1701 return hasFlags(FLAG_IMMUTABLE);
1702 }
1703
1704 /**
1705 * Returns {@code false} if a shortcut is disabled with
1706 * {@link ShortcutManager#disableShortcuts}.
1707 */
1708 public boolean isEnabled() {
Makoto Onuki20c95f82016-05-11 16:51:01 -07001709 return !hasFlags(FLAG_DISABLED);
1710 }
1711
Makoto Onuki22fcc682016-05-17 14:52:19 -07001712 /** @hide */
1713 public boolean isAlive() {
1714 return hasFlags(FLAG_PINNED) || hasFlags(FLAG_DYNAMIC) || hasFlags(FLAG_MANIFEST);
1715 }
1716
1717 /** @hide */
1718 public boolean usesQuota() {
1719 return hasFlags(FLAG_DYNAMIC) || hasFlags(FLAG_MANIFEST);
1720 }
1721
Makoto Onuki20c95f82016-05-11 16:51:01 -07001722 /**
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001723 * Return whether a shortcut's icon is a resource in the owning package.
1724 *
Makoto Onukib5a012f2016-06-21 11:13:53 -07001725 * @hide internal/unit tests only
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001726 */
1727 public boolean hasIconResource() {
1728 return hasFlags(FLAG_HAS_ICON_RES);
1729 }
1730
Makoto Onuki20c95f82016-05-11 16:51:01 -07001731 /** @hide */
1732 public boolean hasStringResources() {
1733 return (mTitleResId != 0) || (mTextResId != 0) || (mDisabledMessageResId != 0);
1734 }
1735
1736 /** @hide */
1737 public boolean hasAnyResources() {
1738 return hasIconResource() || hasStringResources();
1739 }
1740
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001741 /**
1742 * Return whether a shortcut's icon is stored as a file.
1743 *
Makoto Onukib5a012f2016-06-21 11:13:53 -07001744 * @hide internal/unit tests only
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001745 */
1746 public boolean hasIconFile() {
1747 return hasFlags(FLAG_HAS_ICON_FILE);
1748 }
1749
Makoto Onuki55046222016-03-08 10:49:47 -08001750 /**
Hyunyoung Songe4179e22017-03-01 12:51:26 -08001751 * Return whether a shortcut's icon is adaptive bitmap following design guideline
Makoto Onukibf563b62017-05-04 10:25:30 -07001752 * defined in {@link android.graphics.drawable.AdaptiveIconDrawable}.
Hyunyoung Songf281e7a2017-02-13 10:57:42 -08001753 *
1754 * @hide internal/unit tests only
1755 */
Hyunyoung Songe4179e22017-03-01 12:51:26 -08001756 public boolean hasAdaptiveBitmap() {
1757 return hasFlags(FLAG_ADAPTIVE_BITMAP);
Hyunyoung Songf281e7a2017-02-13 10:57:42 -08001758 }
1759
Makoto Onuki475c3652017-05-08 14:29:03 -07001760 /** @hide */
1761 public boolean isIconPendingSave() {
1762 return hasFlags(FLAG_ICON_FILE_PENDING_SAVE);
1763 }
1764
1765 /** @hide */
1766 public void setIconPendingSave() {
1767 addFlags(FLAG_ICON_FILE_PENDING_SAVE);
1768 }
1769
1770 /** @hide */
1771 public void clearIconPendingSave() {
1772 clearFlags(FLAG_ICON_FILE_PENDING_SAVE);
1773 }
1774
Hyunyoung Songf281e7a2017-02-13 10:57:42 -08001775 /**
Makoto Onukia4f89b12017-10-05 10:37:55 -07001776 * When the system wasn't able to restore a shortcut, it'll still be registered to the system
1777 * but disabled, and such shortcuts will not be visible to the publisher. They're still visible
1778 * to launchers though.
1779 *
1780 * @hide
1781 */
1782 @TestApi
1783 public boolean isVisibleToPublisher() {
1784 return !isDisabledForRestoreIssue(mDisabledReason);
1785 }
1786
1787 /**
Makoto Onuki55046222016-03-08 10:49:47 -08001788 * Return whether a shortcut only contains "key" information only or not. If true, only the
1789 * following fields are available.
1790 * <ul>
1791 * <li>{@link #getId()}
Makoto Onuki22fcc682016-05-17 14:52:19 -07001792 * <li>{@link #getPackage()}
Makoto Onuki4d6b87f2016-06-17 13:47:40 -07001793 * <li>{@link #getActivity()}
Makoto Onuki55046222016-03-08 10:49:47 -08001794 * <li>{@link #getLastChangedTimestamp()}
1795 * <li>{@link #isDynamic()}
1796 * <li>{@link #isPinned()}
Makoto Onukib5a012f2016-06-21 11:13:53 -07001797 * <li>{@link #isDeclaredInManifest()}
1798 * <li>{@link #isImmutable()}
1799 * <li>{@link #isEnabled()}
1800 * <li>{@link #getUserHandle()}
Makoto Onuki55046222016-03-08 10:49:47 -08001801 * </ul>
Makoto Onuki4a910962016-07-07 13:57:34 -07001802 *
Makoto Onukife9c9662016-07-25 15:12:23 -07001803 * <p>For performance reasons, shortcuts passed to
1804 * {@link LauncherApps.Callback#onShortcutsChanged(String, List, UserHandle)} as well as those
1805 * returned from {@link LauncherApps#getShortcuts(ShortcutQuery, UserHandle)}
1806 * while using the {@link ShortcutQuery#FLAG_GET_KEY_FIELDS_ONLY} option contain only key
1807 * information.
Makoto Onuki55046222016-03-08 10:49:47 -08001808 */
1809 public boolean hasKeyFieldsOnly() {
1810 return hasFlags(FLAG_KEY_FIELDS_ONLY);
1811 }
1812
Makoto Onukib5a012f2016-06-21 11:13:53 -07001813 /** @hide */
Makoto Onuki20c95f82016-05-11 16:51:01 -07001814 public boolean hasStringResourcesResolved() {
1815 return hasFlags(FLAG_STRINGS_RESOLVED);
1816 }
1817
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001818 /** @hide */
1819 public void updateTimestamp() {
1820 mLastChangedTimestamp = System.currentTimeMillis();
1821 }
1822
1823 /** @hide */
1824 // VisibleForTesting
1825 public void setTimestamp(long value) {
1826 mLastChangedTimestamp = value;
1827 }
1828
1829 /** @hide */
Makoto Onuki55046222016-03-08 10:49:47 -08001830 public void clearIcon() {
1831 mIcon = null;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001832 }
1833
1834 /** @hide */
Makoto Onuki55046222016-03-08 10:49:47 -08001835 public void setIconResourceId(int iconResourceId) {
Makoto Onuki157b1622016-06-02 16:13:10 -07001836 if (mIconResId != iconResourceId) {
1837 mIconResName = null;
1838 }
1839 mIconResId = iconResourceId;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001840 }
1841
Makoto Onukib6d35232016-04-04 15:57:17 -07001842 /**
1843 * Get the resource ID for the icon, valid only when {@link #hasIconResource()} } is true.
Makoto Onukib5a012f2016-06-21 11:13:53 -07001844 * @hide internal / tests only.
Makoto Onukib6d35232016-04-04 15:57:17 -07001845 */
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001846 public int getIconResourceId() {
Makoto Onuki157b1622016-06-02 16:13:10 -07001847 return mIconResId;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001848 }
1849
Makoto Onuki475c3652017-05-08 14:29:03 -07001850 /**
1851 * Bitmap path. Note this will be null even if {@link #hasIconFile()} is set when the save
1852 * is pending. Use {@link #isIconPendingSave()} to check it.
1853 *
1854 * @hide
1855 */
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001856 public String getBitmapPath() {
1857 return mBitmapPath;
1858 }
1859
1860 /** @hide */
1861 public void setBitmapPath(String bitmapPath) {
1862 mBitmapPath = bitmapPath;
1863 }
1864
Makoto Onuki22fcc682016-05-17 14:52:19 -07001865 /** @hide */
1866 public void setDisabledMessageResId(int disabledMessageResId) {
Makoto Onuki157b1622016-06-02 16:13:10 -07001867 if (mDisabledMessageResId != disabledMessageResId) {
1868 mDisabledMessageResName = null;
1869 }
Makoto Onuki22fcc682016-05-17 14:52:19 -07001870 mDisabledMessageResId = disabledMessageResId;
1871 mDisabledMessage = null;
1872 }
1873
1874 /** @hide */
1875 public void setDisabledMessage(String disabledMessage) {
1876 mDisabledMessage = disabledMessage;
1877 mDisabledMessageResId = 0;
Makoto Onuki157b1622016-06-02 16:13:10 -07001878 mDisabledMessageResName = null;
1879 }
1880
1881 /** @hide */
1882 public String getTitleResName() {
1883 return mTitleResName;
1884 }
1885
1886 /** @hide */
1887 public void setTitleResName(String titleResName) {
1888 mTitleResName = titleResName;
1889 }
1890
1891 /** @hide */
1892 public String getTextResName() {
1893 return mTextResName;
1894 }
1895
1896 /** @hide */
1897 public void setTextResName(String textResName) {
1898 mTextResName = textResName;
1899 }
1900
1901 /** @hide */
1902 public String getDisabledMessageResName() {
1903 return mDisabledMessageResName;
1904 }
1905
1906 /** @hide */
1907 public void setDisabledMessageResName(String disabledMessageResName) {
1908 mDisabledMessageResName = disabledMessageResName;
1909 }
1910
1911 /** @hide */
1912 public String getIconResName() {
1913 return mIconResName;
1914 }
1915
1916 /** @hide */
1917 public void setIconResName(String iconResName) {
1918 mIconResName = iconResName;
Makoto Onuki22fcc682016-05-17 14:52:19 -07001919 }
1920
Makoto Onukidf6da042016-06-16 09:51:40 -07001921 /**
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001922 * Replaces the intent.
Makoto Onukidf6da042016-06-16 09:51:40 -07001923 *
1924 * @throws IllegalArgumentException when extra is not compatible with {@link PersistableBundle}.
1925 *
1926 * @hide
1927 */
Makoto Onuki440a1ea2016-07-20 14:21:18 -07001928 public void setIntents(Intent[] intents) throws IllegalArgumentException {
1929 Preconditions.checkNotNull(intents);
1930 Preconditions.checkArgument(intents.length > 0);
Makoto Onukidf6da042016-06-16 09:51:40 -07001931
Makoto Onuki440a1ea2016-07-20 14:21:18 -07001932 mIntents = cloneIntents(intents);
1933 fixUpIntentExtras();
1934 }
Makoto Onukidf6da042016-06-16 09:51:40 -07001935
Makoto Onuki440a1ea2016-07-20 14:21:18 -07001936 /** @hide */
1937 public static Intent setIntentExtras(Intent intent, PersistableBundle extras) {
1938 if (extras == null) {
Makoto Onukidf6da042016-06-16 09:51:40 -07001939 intent.replaceExtras((Bundle) null);
Makoto Onukidf6da042016-06-16 09:51:40 -07001940 } else {
Makoto Onuki440a1ea2016-07-20 14:21:18 -07001941 intent.replaceExtras(new Bundle(extras));
Makoto Onukidf6da042016-06-16 09:51:40 -07001942 }
Makoto Onuki440a1ea2016-07-20 14:21:18 -07001943 return intent;
Makoto Onukidf6da042016-06-16 09:51:40 -07001944 }
1945
1946 /**
1947 * Replaces the categories.
1948 *
1949 * @hide
1950 */
1951 public void setCategories(Set<String> categories) {
1952 mCategories = cloneCategories(categories);
1953 }
1954
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001955 private ShortcutInfo(Parcel source) {
1956 final ClassLoader cl = getClass().getClassLoader();
1957
Makoto Onukiabe84422016-04-07 09:41:19 -07001958 mUserId = source.readInt();
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001959 mId = source.readString();
1960 mPackageName = source.readString();
Makoto Onuki22fcc682016-05-17 14:52:19 -07001961 mActivity = source.readParcelable(cl);
Makoto Onuki4d6b87f2016-06-17 13:47:40 -07001962 mFlags = source.readInt();
1963 mIconResId = source.readInt();
1964 mLastChangedTimestamp = source.readLong();
Makoto Onukia4f89b12017-10-05 10:37:55 -07001965 mDisabledReason = source.readInt();
Makoto Onuki4d6b87f2016-06-17 13:47:40 -07001966
1967 if (source.readInt() == 0) {
1968 return; // key information only.
1969 }
1970
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001971 mIcon = source.readParcelable(cl);
Makoto Onuki22fcc682016-05-17 14:52:19 -07001972 mTitle = source.readCharSequence();
Makoto Onuki20c95f82016-05-11 16:51:01 -07001973 mTitleResId = source.readInt();
Makoto Onuki22fcc682016-05-17 14:52:19 -07001974 mText = source.readCharSequence();
Makoto Onuki20c95f82016-05-11 16:51:01 -07001975 mTextResId = source.readInt();
Makoto Onuki22fcc682016-05-17 14:52:19 -07001976 mDisabledMessage = source.readCharSequence();
Makoto Onuki20c95f82016-05-11 16:51:01 -07001977 mDisabledMessageResId = source.readInt();
Makoto Onuki440a1ea2016-07-20 14:21:18 -07001978 mIntents = source.readParcelableArray(cl, Intent.class);
1979 mIntentPersistableExtrases = source.readParcelableArray(cl, PersistableBundle.class);
Makoto Onuki20c95f82016-05-11 16:51:01 -07001980 mRank = source.readInt();
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001981 mExtras = source.readParcelable(cl);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001982 mBitmapPath = source.readString();
Makoto Onukibe73a802016-04-15 14:46:35 -07001983
Makoto Onuki157b1622016-06-02 16:13:10 -07001984 mIconResName = source.readString();
1985 mTitleResName = source.readString();
1986 mTextResName = source.readString();
1987 mDisabledMessageResName = source.readString();
1988
Makoto Onukibe73a802016-04-15 14:46:35 -07001989 int N = source.readInt();
1990 if (N == 0) {
1991 mCategories = null;
1992 } else {
1993 mCategories = new ArraySet<>(N);
1994 for (int i = 0; i < N; i++) {
1995 mCategories.add(source.readString().intern());
1996 }
1997 }
Mehdi Alizadeh14242af2018-12-20 20:11:35 -08001998
1999 mPersons = source.readParcelableArray(cl, Person.class);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002000 }
2001
2002 @Override
2003 public void writeToParcel(Parcel dest, int flags) {
Makoto Onukiabe84422016-04-07 09:41:19 -07002004 dest.writeInt(mUserId);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002005 dest.writeString(mId);
2006 dest.writeString(mPackageName);
Makoto Onuki22fcc682016-05-17 14:52:19 -07002007 dest.writeParcelable(mActivity, flags);
Makoto Onuki4d6b87f2016-06-17 13:47:40 -07002008 dest.writeInt(mFlags);
2009 dest.writeInt(mIconResId);
2010 dest.writeLong(mLastChangedTimestamp);
Makoto Onukia4f89b12017-10-05 10:37:55 -07002011 dest.writeInt(mDisabledReason);
Makoto Onuki4d6b87f2016-06-17 13:47:40 -07002012
2013 if (hasKeyFieldsOnly()) {
2014 dest.writeInt(0);
2015 return;
2016 }
2017 dest.writeInt(1);
2018
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002019 dest.writeParcelable(mIcon, flags);
Makoto Onuki22fcc682016-05-17 14:52:19 -07002020 dest.writeCharSequence(mTitle);
Makoto Onuki20c95f82016-05-11 16:51:01 -07002021 dest.writeInt(mTitleResId);
Makoto Onuki22fcc682016-05-17 14:52:19 -07002022 dest.writeCharSequence(mText);
Makoto Onuki20c95f82016-05-11 16:51:01 -07002023 dest.writeInt(mTextResId);
Makoto Onuki22fcc682016-05-17 14:52:19 -07002024 dest.writeCharSequence(mDisabledMessage);
Makoto Onuki20c95f82016-05-11 16:51:01 -07002025 dest.writeInt(mDisabledMessageResId);
Makoto Onukibe73a802016-04-15 14:46:35 -07002026
Makoto Onuki440a1ea2016-07-20 14:21:18 -07002027 dest.writeParcelableArray(mIntents, flags);
2028 dest.writeParcelableArray(mIntentPersistableExtrases, flags);
Makoto Onuki20c95f82016-05-11 16:51:01 -07002029 dest.writeInt(mRank);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002030 dest.writeParcelable(mExtras, flags);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002031 dest.writeString(mBitmapPath);
Makoto Onukibe73a802016-04-15 14:46:35 -07002032
Makoto Onuki157b1622016-06-02 16:13:10 -07002033 dest.writeString(mIconResName);
2034 dest.writeString(mTitleResName);
2035 dest.writeString(mTextResName);
2036 dest.writeString(mDisabledMessageResName);
2037
Makoto Onukibe73a802016-04-15 14:46:35 -07002038 if (mCategories != null) {
2039 final int N = mCategories.size();
2040 dest.writeInt(N);
2041 for (int i = 0; i < N; i++) {
2042 dest.writeString(mCategories.valueAt(i));
2043 }
2044 } else {
2045 dest.writeInt(0);
2046 }
Mehdi Alizadeh14242af2018-12-20 20:11:35 -08002047
2048 dest.writeParcelableArray(mPersons, flags);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002049 }
2050
2051 public static final Creator<ShortcutInfo> CREATOR =
2052 new Creator<ShortcutInfo>() {
2053 public ShortcutInfo createFromParcel(Parcel source) {
2054 return new ShortcutInfo(source);
2055 }
2056 public ShortcutInfo[] newArray(int size) {
2057 return new ShortcutInfo[size];
2058 }
2059 };
2060
2061 @Override
2062 public int describeContents() {
2063 return 0;
2064 }
2065
Makoto Onuki6208c672017-10-02 16:20:35 -07002066
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002067 /**
2068 * Return a string representation, intended for logging. Some fields will be retracted.
2069 */
2070 @Override
2071 public String toString() {
Makoto Onuki6208c672017-10-02 16:20:35 -07002072 return toStringInner(/* secure =*/ true, /* includeInternalData =*/ false,
2073 /*indent=*/ null);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002074 }
2075
2076 /** @hide */
2077 public String toInsecureString() {
Makoto Onuki6208c672017-10-02 16:20:35 -07002078 return toStringInner(/* secure =*/ false, /* includeInternalData =*/ true,
2079 /*indent=*/ null);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002080 }
2081
Makoto Onuki6208c672017-10-02 16:20:35 -07002082 /** @hide */
2083 public String toDumpString(String indent) {
2084 return toStringInner(/* secure =*/ false, /* includeInternalData =*/ true, indent);
2085 }
2086
2087 private void addIndentOrComma(StringBuilder sb, String indent) {
2088 if (indent != null) {
2089 sb.append("\n ");
2090 sb.append(indent);
2091 } else {
2092 sb.append(", ");
2093 }
2094 }
2095
2096 private String toStringInner(boolean secure, boolean includeInternalData, String indent) {
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002097 final StringBuilder sb = new StringBuilder();
Makoto Onuki6208c672017-10-02 16:20:35 -07002098
2099 if (indent != null) {
2100 sb.append(indent);
2101 }
2102
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002103 sb.append("ShortcutInfo {");
2104
2105 sb.append("id=");
2106 sb.append(secure ? "***" : mId);
2107
Makoto Onuki22fcc682016-05-17 14:52:19 -07002108 sb.append(", flags=0x");
2109 sb.append(Integer.toHexString(mFlags));
2110 sb.append(" [");
Makoto Onukia4f89b12017-10-05 10:37:55 -07002111 if ((mFlags & FLAG_SHADOW) != 0) {
2112 // Note the shadow flag isn't actually used anywhere and it's just for dumpsys, so
2113 // we don't have an isXxx for this.
2114 sb.append("Sdw");
2115 }
Makoto Onuki22fcc682016-05-17 14:52:19 -07002116 if (!isEnabled()) {
Makoto Onuki6208c672017-10-02 16:20:35 -07002117 sb.append("Dis");
Makoto Onuki22fcc682016-05-17 14:52:19 -07002118 }
2119 if (isImmutable()) {
2120 sb.append("Im");
2121 }
2122 if (isManifestShortcut()) {
Makoto Onuki6208c672017-10-02 16:20:35 -07002123 sb.append("Man");
Makoto Onuki22fcc682016-05-17 14:52:19 -07002124 }
2125 if (isDynamic()) {
Makoto Onuki6208c672017-10-02 16:20:35 -07002126 sb.append("Dyn");
Makoto Onuki22fcc682016-05-17 14:52:19 -07002127 }
2128 if (isPinned()) {
Makoto Onuki6208c672017-10-02 16:20:35 -07002129 sb.append("Pin");
Makoto Onuki22fcc682016-05-17 14:52:19 -07002130 }
2131 if (hasIconFile()) {
Makoto Onuki6208c672017-10-02 16:20:35 -07002132 sb.append("Ic-f");
Makoto Onuki22fcc682016-05-17 14:52:19 -07002133 }
Makoto Onuki475c3652017-05-08 14:29:03 -07002134 if (isIconPendingSave()) {
Makoto Onuki6208c672017-10-02 16:20:35 -07002135 sb.append("Pens");
Makoto Onuki475c3652017-05-08 14:29:03 -07002136 }
Makoto Onuki22fcc682016-05-17 14:52:19 -07002137 if (hasIconResource()) {
Makoto Onuki6208c672017-10-02 16:20:35 -07002138 sb.append("Ic-r");
Makoto Onuki22fcc682016-05-17 14:52:19 -07002139 }
2140 if (hasKeyFieldsOnly()) {
Makoto Onuki6208c672017-10-02 16:20:35 -07002141 sb.append("Key");
Makoto Onuki22fcc682016-05-17 14:52:19 -07002142 }
2143 if (hasStringResourcesResolved()) {
Makoto Onuki6208c672017-10-02 16:20:35 -07002144 sb.append("Str");
Makoto Onuki22fcc682016-05-17 14:52:19 -07002145 }
Makoto Onukibf563b62017-05-04 10:25:30 -07002146 if (isReturnedByServer()) {
Makoto Onuki6208c672017-10-02 16:20:35 -07002147 sb.append("Rets");
Makoto Onukibf563b62017-05-04 10:25:30 -07002148 }
Mehdi Alizadeh14242af2018-12-20 20:11:35 -08002149 if (isLongLived()) {
2150 sb.append("Liv");
2151 }
Makoto Onuki22fcc682016-05-17 14:52:19 -07002152 sb.append("]");
2153
Makoto Onuki6208c672017-10-02 16:20:35 -07002154 addIndentOrComma(sb, indent);
2155
2156 sb.append("packageName=");
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002157 sb.append(mPackageName);
2158
Makoto Onukia4f89b12017-10-05 10:37:55 -07002159 addIndentOrComma(sb, indent);
2160
2161 sb.append("activity=");
Makoto Onuki22fcc682016-05-17 14:52:19 -07002162 sb.append(mActivity);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002163
Makoto Onuki6208c672017-10-02 16:20:35 -07002164 addIndentOrComma(sb, indent);
2165
2166 sb.append("shortLabel=");
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002167 sb.append(secure ? "***" : mTitle);
Makoto Onukieddbfec2016-05-31 17:04:34 -07002168 sb.append(", resId=");
Makoto Onuki20c95f82016-05-11 16:51:01 -07002169 sb.append(mTitleResId);
Makoto Onuki157b1622016-06-02 16:13:10 -07002170 sb.append("[");
2171 sb.append(mTitleResName);
2172 sb.append("]");
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002173
Makoto Onuki6208c672017-10-02 16:20:35 -07002174 addIndentOrComma(sb, indent);
2175
2176 sb.append("longLabel=");
Makoto Onukie3ae7ec2016-03-29 15:45:25 -07002177 sb.append(secure ? "***" : mText);
Makoto Onukieddbfec2016-05-31 17:04:34 -07002178 sb.append(", resId=");
Makoto Onuki20c95f82016-05-11 16:51:01 -07002179 sb.append(mTextResId);
Makoto Onuki157b1622016-06-02 16:13:10 -07002180 sb.append("[");
2181 sb.append(mTextResName);
2182 sb.append("]");
Makoto Onuki20c95f82016-05-11 16:51:01 -07002183
Makoto Onuki6208c672017-10-02 16:20:35 -07002184 addIndentOrComma(sb, indent);
2185
2186 sb.append("disabledMessage=");
Makoto Onuki20c95f82016-05-11 16:51:01 -07002187 sb.append(secure ? "***" : mDisabledMessage);
Makoto Onukieddbfec2016-05-31 17:04:34 -07002188 sb.append(", resId=");
Makoto Onuki20c95f82016-05-11 16:51:01 -07002189 sb.append(mDisabledMessageResId);
Makoto Onuki157b1622016-06-02 16:13:10 -07002190 sb.append("[");
2191 sb.append(mDisabledMessageResName);
2192 sb.append("]");
Makoto Onukie3ae7ec2016-03-29 15:45:25 -07002193
Makoto Onuki6208c672017-10-02 16:20:35 -07002194 addIndentOrComma(sb, indent);
2195
Makoto Onukia4f89b12017-10-05 10:37:55 -07002196 sb.append("disabledReason=");
Makoto Onukib1588c02017-10-12 15:11:45 -07002197 sb.append(getDisabledReasonDebugString(mDisabledReason));
Makoto Onukia4f89b12017-10-05 10:37:55 -07002198
2199 addIndentOrComma(sb, indent);
2200
Makoto Onuki6208c672017-10-02 16:20:35 -07002201 sb.append("categories=");
Makoto Onukib6d35232016-04-04 15:57:17 -07002202 sb.append(mCategories);
2203
Makoto Onuki6208c672017-10-02 16:20:35 -07002204 addIndentOrComma(sb, indent);
2205
Mehdi Alizadeh14242af2018-12-20 20:11:35 -08002206 sb.append("persons=");
2207 sb.append(mPersons);
2208
2209 addIndentOrComma(sb, indent);
2210
Makoto Onuki6208c672017-10-02 16:20:35 -07002211 sb.append("icon=");
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002212 sb.append(mIcon);
2213
Makoto Onuki6208c672017-10-02 16:20:35 -07002214 addIndentOrComma(sb, indent);
2215
2216 sb.append("rank=");
Makoto Onuki20c95f82016-05-11 16:51:01 -07002217 sb.append(mRank);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002218
2219 sb.append(", timestamp=");
2220 sb.append(mLastChangedTimestamp);
2221
Makoto Onuki6208c672017-10-02 16:20:35 -07002222 addIndentOrComma(sb, indent);
2223
2224 sb.append("intents=");
Makoto Onuki440a1ea2016-07-20 14:21:18 -07002225 if (mIntents == null) {
2226 sb.append("null");
2227 } else {
2228 if (secure) {
2229 sb.append("size:");
2230 sb.append(mIntents.length);
2231 } else {
2232 final int size = mIntents.length;
2233 sb.append("[");
2234 String sep = "";
2235 for (int i = 0; i < size; i++) {
2236 sb.append(sep);
2237 sep = ", ";
2238 sb.append(mIntents[i]);
2239 sb.append("/");
2240 sb.append(mIntentPersistableExtrases[i]);
2241 }
2242 sb.append("]");
2243 }
2244 }
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002245
Makoto Onuki6208c672017-10-02 16:20:35 -07002246 addIndentOrComma(sb, indent);
2247
2248 sb.append("extras=");
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002249 sb.append(mExtras);
2250
2251 if (includeInternalData) {
Makoto Onuki6208c672017-10-02 16:20:35 -07002252 addIndentOrComma(sb, indent);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002253
Makoto Onuki6208c672017-10-02 16:20:35 -07002254 sb.append("iconRes=");
Makoto Onuki157b1622016-06-02 16:13:10 -07002255 sb.append(mIconResId);
2256 sb.append("[");
2257 sb.append(mIconResName);
2258 sb.append("]");
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002259
2260 sb.append(", bitmapPath=");
2261 sb.append(mBitmapPath);
2262 }
2263
2264 sb.append("}");
2265 return sb.toString();
2266 }
2267
2268 /** @hide */
Makoto Onukiabe84422016-04-07 09:41:19 -07002269 public ShortcutInfo(
Makoto Onuki22fcc682016-05-17 14:52:19 -07002270 @UserIdInt int userId, String id, String packageName, ComponentName activity,
Makoto Onuki157b1622016-06-02 16:13:10 -07002271 Icon icon, CharSequence title, int titleResId, String titleResName,
2272 CharSequence text, int textResId, String textResName,
2273 CharSequence disabledMessage, int disabledMessageResId, String disabledMessageResName,
Makoto Onuki440a1ea2016-07-20 14:21:18 -07002274 Set<String> categories, Intent[] intentsWithExtras, int rank, PersistableBundle extras,
2275 long lastChangedTimestamp,
Mehdi Alizadehebb4b602019-02-05 15:52:18 -08002276 int flags, int iconResId, String iconResName, String bitmapPath, int disabledReason,
2277 Person[] persons) {
Makoto Onukiabe84422016-04-07 09:41:19 -07002278 mUserId = userId;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002279 mId = id;
2280 mPackageName = packageName;
Makoto Onuki22fcc682016-05-17 14:52:19 -07002281 mActivity = activity;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002282 mIcon = icon;
2283 mTitle = title;
Makoto Onuki20c95f82016-05-11 16:51:01 -07002284 mTitleResId = titleResId;
Makoto Onuki157b1622016-06-02 16:13:10 -07002285 mTitleResName = titleResName;
Makoto Onukie3ae7ec2016-03-29 15:45:25 -07002286 mText = text;
Makoto Onuki20c95f82016-05-11 16:51:01 -07002287 mTextResId = textResId;
Makoto Onuki157b1622016-06-02 16:13:10 -07002288 mTextResName = textResName;
Makoto Onuki20c95f82016-05-11 16:51:01 -07002289 mDisabledMessage = disabledMessage;
2290 mDisabledMessageResId = disabledMessageResId;
Makoto Onuki157b1622016-06-02 16:13:10 -07002291 mDisabledMessageResName = disabledMessageResName;
Makoto Onukidf6da042016-06-16 09:51:40 -07002292 mCategories = cloneCategories(categories);
Makoto Onuki440a1ea2016-07-20 14:21:18 -07002293 mIntents = cloneIntents(intentsWithExtras);
2294 fixUpIntentExtras();
Makoto Onuki20c95f82016-05-11 16:51:01 -07002295 mRank = rank;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002296 mExtras = extras;
2297 mLastChangedTimestamp = lastChangedTimestamp;
2298 mFlags = flags;
Makoto Onuki157b1622016-06-02 16:13:10 -07002299 mIconResId = iconResId;
2300 mIconResName = iconResName;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002301 mBitmapPath = bitmapPath;
Makoto Onukia4f89b12017-10-05 10:37:55 -07002302 mDisabledReason = disabledReason;
Mehdi Alizadehebb4b602019-02-05 15:52:18 -08002303 mPersons = persons;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002304 }
2305}