blob: d5fb848c269217c5ae4b372ae64d33738b104d35 [file] [log] [blame]
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package android.content.pm;
17
18import android.annotation.IntDef;
19import android.annotation.NonNull;
20import android.annotation.Nullable;
Mehdi Alizadeh88873652019-02-04 14:16:46 -080021import android.annotation.SystemApi;
Makoto Onukia4f89b12017-10-05 10:37:55 -070022import android.annotation.TestApi;
Makoto Onukiabe84422016-04-07 09:41:19 -070023import android.annotation.UserIdInt;
Felipe Leme90205ef2019-03-05 09:59:52 -080024import android.app.Notification;
Mehdi Alizadeh14242af2018-12-20 20:11:35 -080025import android.app.Person;
Makoto Onuki347a6bd2016-07-19 11:13:08 -070026import android.app.TaskStackBuilder;
Artur Satayeve23a0eb2019-12-10 17:47:52 +000027import android.compat.annotation.UnsupportedAppUsage;
Makoto Onuki6f7362d92016-03-04 13:39:41 -080028import android.content.ComponentName;
29import android.content.Context;
30import android.content.Intent;
Felipe Leme90205ef2019-03-05 09:59:52 -080031import android.content.LocusId;
Makoto Onuki4a910962016-07-07 13:57:34 -070032import android.content.pm.LauncherApps.ShortcutQuery;
Makoto Onuki20c95f82016-05-11 16:51:01 -070033import android.content.res.Resources;
Makoto Onuki157b1622016-06-02 16:13:10 -070034import android.content.res.Resources.NotFoundException;
Makoto Onuki4a910962016-07-07 13:57:34 -070035import android.graphics.Bitmap;
Makoto Onuki6f7362d92016-03-04 13:39:41 -080036import android.graphics.drawable.Icon;
Mathew Inwood8c854f82018-09-14 12:35:36 +010037import android.os.Build;
Makoto Onuki55046222016-03-08 10:49:47 -080038import android.os.Bundle;
Makoto Onuki6f7362d92016-03-04 13:39:41 -080039import android.os.Parcel;
40import android.os.Parcelable;
41import android.os.PersistableBundle;
42import android.os.UserHandle;
Makoto Onukidf6da042016-06-16 09:51:40 -070043import android.text.TextUtils;
Makoto Onukibe73a802016-04-15 14:46:35 -070044import android.util.ArraySet;
Makoto Onuki157b1622016-06-02 16:13:10 -070045import android.util.Log;
Felipe Leme90205ef2019-03-05 09:59:52 -080046import android.view.contentcapture.ContentCaptureContext;
Makoto Onuki6f7362d92016-03-04 13:39:41 -080047
Makoto Onuki157b1622016-06-02 16:13:10 -070048import com.android.internal.annotations.VisibleForTesting;
Makoto Onuki6f7362d92016-03-04 13:39:41 -080049import com.android.internal.util.Preconditions;
50
51import java.lang.annotation.Retention;
52import java.lang.annotation.RetentionPolicy;
Makoto Onukib5a012f2016-06-21 11:13:53 -070053import java.util.List;
Daulet Zhanguzina2044e12019-12-30 16:34:59 +000054import java.util.Objects;
Makoto Onukibe73a802016-04-15 14:46:35 -070055import java.util.Set;
Makoto Onuki6f7362d92016-03-04 13:39:41 -080056
57/**
Kevin Hufnagle68d699d2016-10-14 19:04:51 -070058 * Represents a shortcut that can be published via {@link ShortcutManager}.
Makoto Onuki6f7362d92016-03-04 13:39:41 -080059 *
Makoto Onuki4a910962016-07-07 13:57:34 -070060 * @see ShortcutManager
Makoto Onuki6f7362d92016-03-04 13:39:41 -080061 */
Jeff Sharkey70168dd2016-03-30 21:47:16 -060062public final class ShortcutInfo implements Parcelable {
Makoto Onuki157b1622016-06-02 16:13:10 -070063 static final String TAG = "Shortcut";
64
65 private static final String RES_TYPE_STRING = "string";
66
67 private static final String ANDROID_PACKAGE_NAME = "android";
68
Makoto Onuki9e1f5592016-06-08 12:30:23 -070069 private static final int IMPLICIT_RANK_MASK = 0x7fffffff;
70
71 private static final int RANK_CHANGED_BIT = ~IMPLICIT_RANK_MASK;
72
73 /** @hide */
74 public static final int RANK_NOT_SET = Integer.MAX_VALUE;
75
Makoto Onuki157b1622016-06-02 16:13:10 -070076 /** @hide */
Makoto Onuki6f7362d92016-03-04 13:39:41 -080077 public static final int FLAG_DYNAMIC = 1 << 0;
78
Makoto Onuki157b1622016-06-02 16:13:10 -070079 /** @hide */
Makoto Onuki6f7362d92016-03-04 13:39:41 -080080 public static final int FLAG_PINNED = 1 << 1;
81
Makoto Onuki157b1622016-06-02 16:13:10 -070082 /** @hide */
Makoto Onuki6f7362d92016-03-04 13:39:41 -080083 public static final int FLAG_HAS_ICON_RES = 1 << 2;
84
Makoto Onuki157b1622016-06-02 16:13:10 -070085 /** @hide */
Makoto Onuki6f7362d92016-03-04 13:39:41 -080086 public static final int FLAG_HAS_ICON_FILE = 1 << 3;
87
Makoto Onuki157b1622016-06-02 16:13:10 -070088 /** @hide */
Makoto Onuki55046222016-03-08 10:49:47 -080089 public static final int FLAG_KEY_FIELDS_ONLY = 1 << 4;
90
Makoto Onuki157b1622016-06-02 16:13:10 -070091 /** @hide */
Makoto Onuki22fcc682016-05-17 14:52:19 -070092 public static final int FLAG_MANIFEST = 1 << 5;
Makoto Onuki20c95f82016-05-11 16:51:01 -070093
Makoto Onuki157b1622016-06-02 16:13:10 -070094 /** @hide */
Makoto Onuki20c95f82016-05-11 16:51:01 -070095 public static final int FLAG_DISABLED = 1 << 6;
96
Makoto Onuki157b1622016-06-02 16:13:10 -070097 /** @hide */
Makoto Onuki20c95f82016-05-11 16:51:01 -070098 public static final int FLAG_STRINGS_RESOLVED = 1 << 7;
99
Makoto Onuki157b1622016-06-02 16:13:10 -0700100 /** @hide */
Makoto Onuki22fcc682016-05-17 14:52:19 -0700101 public static final int FLAG_IMMUTABLE = 1 << 8;
102
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800103 /** @hide */
Hyunyoung Songe4179e22017-03-01 12:51:26 -0800104 public static final int FLAG_ADAPTIVE_BITMAP = 1 << 9;
Hyunyoung Songf281e7a2017-02-13 10:57:42 -0800105
106 /** @hide */
Makoto Onukibf563b62017-05-04 10:25:30 -0700107 public static final int FLAG_RETURNED_BY_SERVICE = 1 << 10;
108
Makoto Onuki475c3652017-05-08 14:29:03 -0700109 /** @hide When this is set, the bitmap icon is waiting to be saved. */
110 public static final int FLAG_ICON_FILE_PENDING_SAVE = 1 << 11;
111
Makoto Onukia4f89b12017-10-05 10:37:55 -0700112 /**
113 * "Shadow" shortcuts are the ones that are restored, but the owner package hasn't been
114 * installed yet.
115 * @hide
116 */
117 public static final int FLAG_SHADOW = 1 << 12;
118
Makoto Onukibf563b62017-05-04 10:25:30 -0700119 /** @hide */
Mehdi Alizadeh14242af2018-12-20 20:11:35 -0800120 public static final int FLAG_LONG_LIVED = 1 << 13;
121
122 /** @hide */
Jeff Sharkeyce8db992017-12-13 20:05:05 -0700123 @IntDef(flag = true, prefix = { "FLAG_" }, value = {
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800124 FLAG_DYNAMIC,
125 FLAG_PINNED,
126 FLAG_HAS_ICON_RES,
127 FLAG_HAS_ICON_FILE,
Makoto Onuki55046222016-03-08 10:49:47 -0800128 FLAG_KEY_FIELDS_ONLY,
Makoto Onuki22fcc682016-05-17 14:52:19 -0700129 FLAG_MANIFEST,
Makoto Onuki20c95f82016-05-11 16:51:01 -0700130 FLAG_DISABLED,
131 FLAG_STRINGS_RESOLVED,
Makoto Onuki22fcc682016-05-17 14:52:19 -0700132 FLAG_IMMUTABLE,
Hyunyoung Songe4179e22017-03-01 12:51:26 -0800133 FLAG_ADAPTIVE_BITMAP,
Makoto Onuki475c3652017-05-08 14:29:03 -0700134 FLAG_RETURNED_BY_SERVICE,
135 FLAG_ICON_FILE_PENDING_SAVE,
Mehdi Alizadeh14242af2018-12-20 20:11:35 -0800136 FLAG_SHADOW,
137 FLAG_LONG_LIVED,
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800138 })
139 @Retention(RetentionPolicy.SOURCE)
140 public @interface ShortcutFlags {}
141
142 // Cloning options.
143
Makoto Onuki157b1622016-06-02 16:13:10 -0700144 /** @hide */
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800145 private static final int CLONE_REMOVE_ICON = 1 << 0;
146
Makoto Onuki157b1622016-06-02 16:13:10 -0700147 /** @hide */
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800148 private static final int CLONE_REMOVE_INTENT = 1 << 1;
149
Makoto Onuki157b1622016-06-02 16:13:10 -0700150 /** @hide */
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800151 public static final int CLONE_REMOVE_NON_KEY_INFO = 1 << 2;
152
Makoto Onuki157b1622016-06-02 16:13:10 -0700153 /** @hide */
154 public static final int CLONE_REMOVE_RES_NAMES = 1 << 3;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800155
Makoto Onuki157b1622016-06-02 16:13:10 -0700156 /** @hide */
Mehdi Alizadehc6096022019-05-27 12:17:36 -0700157 public static final int CLONE_REMOVE_PERSON = 1 << 4;
158
159 /** @hide */
Makoto Onuki157b1622016-06-02 16:13:10 -0700160 public static final int CLONE_REMOVE_FOR_CREATOR = CLONE_REMOVE_ICON | CLONE_REMOVE_RES_NAMES;
161
162 /** @hide */
163 public static final int CLONE_REMOVE_FOR_LAUNCHER = CLONE_REMOVE_ICON | CLONE_REMOVE_INTENT
Mehdi Alizadehc6096022019-05-27 12:17:36 -0700164 | CLONE_REMOVE_RES_NAMES | CLONE_REMOVE_PERSON;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800165
166 /** @hide */
Makoto Onukia01f4f02016-12-15 15:58:41 -0800167 public static final int CLONE_REMOVE_FOR_LAUNCHER_APPROVAL = CLONE_REMOVE_INTENT
Mehdi Alizadehc6096022019-05-27 12:17:36 -0700168 | CLONE_REMOVE_RES_NAMES | CLONE_REMOVE_PERSON;
169
170 /** @hide */
171 public static final int CLONE_REMOVE_FOR_APP_PREDICTION = CLONE_REMOVE_ICON
Makoto Onukia01f4f02016-12-15 15:58:41 -0800172 | CLONE_REMOVE_RES_NAMES;
173
174 /** @hide */
Jeff Sharkeyce8db992017-12-13 20:05:05 -0700175 @IntDef(flag = true, prefix = { "CLONE_" }, value = {
176 CLONE_REMOVE_ICON,
177 CLONE_REMOVE_INTENT,
178 CLONE_REMOVE_NON_KEY_INFO,
179 CLONE_REMOVE_RES_NAMES,
Mehdi Alizadehc6096022019-05-27 12:17:36 -0700180 CLONE_REMOVE_PERSON,
Jeff Sharkeyce8db992017-12-13 20:05:05 -0700181 CLONE_REMOVE_FOR_CREATOR,
Mehdi Alizadehc6096022019-05-27 12:17:36 -0700182 CLONE_REMOVE_FOR_LAUNCHER,
183 CLONE_REMOVE_FOR_LAUNCHER_APPROVAL,
184 CLONE_REMOVE_FOR_APP_PREDICTION
Jeff Sharkeyce8db992017-12-13 20:05:05 -0700185 })
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800186 @Retention(RetentionPolicy.SOURCE)
187 public @interface CloneFlags {}
188
Makoto Onukib6d35232016-04-04 15:57:17 -0700189 /**
Makoto Onukia4f89b12017-10-05 10:37:55 -0700190 * Shortcut is not disabled.
191 */
192 public static final int DISABLED_REASON_NOT_DISABLED = 0;
193
194 /**
195 * Shortcut has been disabled by the publisher app with the
196 * {@link ShortcutManager#disableShortcuts(List)} API.
197 */
198 public static final int DISABLED_REASON_BY_APP = 1;
199
200 /**
201 * Shortcut has been disabled due to changes to the publisher app. (e.g. a manifest shortcut
202 * no longer exists.)
203 */
204 public static final int DISABLED_REASON_APP_CHANGED = 2;
205
206 /**
Makoto Onuki5482a8e62018-01-09 10:31:08 -0800207 * Shortcut is disabled for an unknown reason.
208 */
209 public static final int DISABLED_REASON_UNKNOWN = 3;
210
211 /**
Makoto Onukia4f89b12017-10-05 10:37:55 -0700212 * A disabled reason that's equal to or bigger than this is due to backup and restore issue.
213 * A shortcut with such a reason wil be visible to the launcher, but not to the publisher.
214 * ({@link #isVisibleToPublisher()} will be false.)
215 */
216 private static final int DISABLED_REASON_RESTORE_ISSUE_START = 100;
217
218 /**
219 * Shortcut has been restored from the previous device, but the publisher app on the current
220 * device is of a lower version. The shortcut will not be usable until the app is upgraded to
221 * the same version or higher.
222 */
223 public static final int DISABLED_REASON_VERSION_LOWER = 100;
224
225 /**
226 * Shortcut has not been restored because the publisher app does not support backup and restore.
227 */
228 public static final int DISABLED_REASON_BACKUP_NOT_SUPPORTED = 101;
229
230 /**
231 * Shortcut has not been restored because the publisher app's signature has changed.
232 */
233 public static final int DISABLED_REASON_SIGNATURE_MISMATCH = 102;
234
235 /**
236 * Shortcut has not been restored for unknown reason.
237 */
238 public static final int DISABLED_REASON_OTHER_RESTORE_ISSUE = 103;
239
240 /** @hide */
Jeff Sharkeyce8db992017-12-13 20:05:05 -0700241 @IntDef(prefix = { "DISABLED_REASON_" }, value = {
Makoto Onukia4f89b12017-10-05 10:37:55 -0700242 DISABLED_REASON_NOT_DISABLED,
243 DISABLED_REASON_BY_APP,
244 DISABLED_REASON_APP_CHANGED,
Makoto Onuki5482a8e62018-01-09 10:31:08 -0800245 DISABLED_REASON_UNKNOWN,
Makoto Onukia4f89b12017-10-05 10:37:55 -0700246 DISABLED_REASON_VERSION_LOWER,
247 DISABLED_REASON_BACKUP_NOT_SUPPORTED,
248 DISABLED_REASON_SIGNATURE_MISMATCH,
249 DISABLED_REASON_OTHER_RESTORE_ISSUE,
Jeff Sharkeyce8db992017-12-13 20:05:05 -0700250 })
Makoto Onukia4f89b12017-10-05 10:37:55 -0700251 @Retention(RetentionPolicy.SOURCE)
252 public @interface DisabledReason{}
253
Makoto Onukib1588c02017-10-12 15:11:45 -0700254 /**
255 * Return a label for disabled reasons, which are *not* supposed to be shown to the user.
256 * @hide
257 */
258 public static String getDisabledReasonDebugString(@DisabledReason int disabledReason) {
Makoto Onukia4f89b12017-10-05 10:37:55 -0700259 switch (disabledReason) {
260 case DISABLED_REASON_NOT_DISABLED:
261 return "[Not disabled]";
262 case DISABLED_REASON_BY_APP:
263 return "[Disabled: by app]";
264 case DISABLED_REASON_APP_CHANGED:
265 return "[Disabled: app changed]";
266 case DISABLED_REASON_VERSION_LOWER:
267 return "[Disabled: lower version]";
268 case DISABLED_REASON_BACKUP_NOT_SUPPORTED:
269 return "[Disabled: backup not supported]";
270 case DISABLED_REASON_SIGNATURE_MISMATCH:
271 return "[Disabled: signature mismatch]";
272 case DISABLED_REASON_OTHER_RESTORE_ISSUE:
273 return "[Disabled: unknown restore issue]";
274 }
275 return "[Disabled: unknown reason:" + disabledReason + "]";
276 }
277
Makoto Onukib1588c02017-10-12 15:11:45 -0700278 /**
279 * Return a label for a disabled reason for shortcuts that are disabled due to a backup and
280 * restore issue. If the reason is not due to backup & restore, then it'll return null.
281 *
282 * This method returns localized, user-facing strings, which will be returned by
283 * {@link #getDisabledMessage()}.
284 *
285 * @hide
286 */
287 public static String getDisabledReasonForRestoreIssue(Context context,
288 @DisabledReason int disabledReason) {
289 final Resources res = context.getResources();
290
291 switch (disabledReason) {
292 case DISABLED_REASON_VERSION_LOWER:
293 return res.getString(
294 com.android.internal.R.string.shortcut_restored_on_lower_version);
295 case DISABLED_REASON_BACKUP_NOT_SUPPORTED:
296 return res.getString(
297 com.android.internal.R.string.shortcut_restore_not_supported);
298 case DISABLED_REASON_SIGNATURE_MISMATCH:
299 return res.getString(
300 com.android.internal.R.string.shortcut_restore_signature_mismatch);
301 case DISABLED_REASON_OTHER_RESTORE_ISSUE:
302 return res.getString(
303 com.android.internal.R.string.shortcut_restore_unknown_issue);
Makoto Onuki5482a8e62018-01-09 10:31:08 -0800304 case DISABLED_REASON_UNKNOWN:
305 return res.getString(
306 com.android.internal.R.string.shortcut_disabled_reason_unknown);
Makoto Onukib1588c02017-10-12 15:11:45 -0700307 }
308 return null;
309 }
310
Makoto Onukia4f89b12017-10-05 10:37:55 -0700311 /** @hide */
312 public static boolean isDisabledForRestoreIssue(@DisabledReason int disabledReason) {
313 return disabledReason >= DISABLED_REASON_RESTORE_ISSUE_START;
314 }
315
316 /**
Makoto Onuki4a910962016-07-07 13:57:34 -0700317 * Shortcut category for messaging related actions, such as chat.
Makoto Onukib6d35232016-04-04 15:57:17 -0700318 */
319 public static final String SHORTCUT_CATEGORY_CONVERSATION = "android.shortcut.conversation";
320
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800321 private final String mId;
322
323 @NonNull
324 private final String mPackageName;
325
326 @Nullable
Makoto Onuki22fcc682016-05-17 14:52:19 -0700327 private ComponentName mActivity;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800328
329 @Nullable
330 private Icon mIcon;
331
Makoto Onuki20c95f82016-05-11 16:51:01 -0700332 private int mTitleResId;
333
Makoto Onuki157b1622016-06-02 16:13:10 -0700334 private String mTitleResName;
335
Makoto Onuki20c95f82016-05-11 16:51:01 -0700336 @Nullable
Makoto Onuki22fcc682016-05-17 14:52:19 -0700337 private CharSequence mTitle;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800338
Makoto Onuki20c95f82016-05-11 16:51:01 -0700339 private int mTextResId;
340
Makoto Onuki157b1622016-06-02 16:13:10 -0700341 private String mTextResName;
342
Makoto Onukie3ae7ec2016-03-29 15:45:25 -0700343 @Nullable
Makoto Onuki22fcc682016-05-17 14:52:19 -0700344 private CharSequence mText;
Makoto Onukie3ae7ec2016-03-29 15:45:25 -0700345
Makoto Onuki20c95f82016-05-11 16:51:01 -0700346 private int mDisabledMessageResId;
347
Makoto Onuki157b1622016-06-02 16:13:10 -0700348 private String mDisabledMessageResName;
349
Makoto Onuki20c95f82016-05-11 16:51:01 -0700350 @Nullable
Makoto Onuki22fcc682016-05-17 14:52:19 -0700351 private CharSequence mDisabledMessage;
Makoto Onuki20c95f82016-05-11 16:51:01 -0700352
353 @Nullable
Makoto Onukibe73a802016-04-15 14:46:35 -0700354 private ArraySet<String> mCategories;
Makoto Onukib6d35232016-04-04 15:57:17 -0700355
Makoto Onuki55046222016-03-08 10:49:47 -0800356 /**
Makoto Onuki440a1ea2016-07-20 14:21:18 -0700357 * Intents *with extras removed*.
Makoto Onuki55046222016-03-08 10:49:47 -0800358 */
Makoto Onuki20c95f82016-05-11 16:51:01 -0700359 @Nullable
Makoto Onuki440a1ea2016-07-20 14:21:18 -0700360 private Intent[] mIntents;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800361
Makoto Onuki55046222016-03-08 10:49:47 -0800362 /**
Makoto Onuki440a1ea2016-07-20 14:21:18 -0700363 * Extras for the intents.
Makoto Onuki55046222016-03-08 10:49:47 -0800364 */
Makoto Onuki20c95f82016-05-11 16:51:01 -0700365 @Nullable
Makoto Onuki440a1ea2016-07-20 14:21:18 -0700366 private PersistableBundle[] mIntentPersistableExtrases;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800367
Mehdi Alizadeh14242af2018-12-20 20:11:35 -0800368 @Nullable
369 private Person[] mPersons;
370
Felipe Leme90205ef2019-03-05 09:59:52 -0800371 @Nullable
372 private LocusId mLocusId;
373
Makoto Onuki20c95f82016-05-11 16:51:01 -0700374 private int mRank;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800375
Makoto Onuki9e1f5592016-06-08 12:30:23 -0700376 /**
377 * Internally used for auto-rank-adjustment.
378 *
379 * RANK_CHANGED_BIT is used to denote that the rank of a shortcut is changing.
380 * The rest of the bits are used to denote the order in which shortcuts are passed to
381 * APIs, which is used to preserve the argument order when ranks are tie.
382 */
383 private int mImplicitRank;
384
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800385 @Nullable
386 private PersistableBundle mExtras;
387
388 private long mLastChangedTimestamp;
389
390 // Internal use only.
391 @ShortcutFlags
392 private int mFlags;
393
394 // Internal use only.
Makoto Onuki157b1622016-06-02 16:13:10 -0700395 private int mIconResId;
396
397 private String mIconResName;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800398
399 // Internal use only.
400 @Nullable
401 private String mBitmapPath;
402
Makoto Onukiabe84422016-04-07 09:41:19 -0700403 private final int mUserId;
404
Makoto Onukia4f89b12017-10-05 10:37:55 -0700405 /** @hide */
406 public static final int VERSION_CODE_UNKNOWN = -1;
407
408 private int mDisabledReason;
409
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800410 private ShortcutInfo(Builder b) {
Makoto Onukiabe84422016-04-07 09:41:19 -0700411 mUserId = b.mContext.getUserId();
412
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800413 mId = Preconditions.checkStringNotEmpty(b.mId, "Shortcut ID must be provided");
414
415 // Note we can't do other null checks here because SM.updateShortcuts() takes partial
416 // information.
417 mPackageName = b.mContext.getPackageName();
Makoto Onuki22fcc682016-05-17 14:52:19 -0700418 mActivity = b.mActivity;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800419 mIcon = b.mIcon;
420 mTitle = b.mTitle;
Makoto Onuki20c95f82016-05-11 16:51:01 -0700421 mTitleResId = b.mTitleResId;
Makoto Onukie3ae7ec2016-03-29 15:45:25 -0700422 mText = b.mText;
Makoto Onuki20c95f82016-05-11 16:51:01 -0700423 mTextResId = b.mTextResId;
424 mDisabledMessage = b.mDisabledMessage;
425 mDisabledMessageResId = b.mDisabledMessageResId;
Makoto Onukidf6da042016-06-16 09:51:40 -0700426 mCategories = cloneCategories(b.mCategories);
Makoto Onuki440a1ea2016-07-20 14:21:18 -0700427 mIntents = cloneIntents(b.mIntents);
428 fixUpIntentExtras();
Mehdi Alizadeh14242af2018-12-20 20:11:35 -0800429 mPersons = clonePersons(b.mPersons);
430 if (b.mIsLongLived) {
431 setLongLived();
432 }
Makoto Onuki20c95f82016-05-11 16:51:01 -0700433 mRank = b.mRank;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800434 mExtras = b.mExtras;
Felipe Leme90205ef2019-03-05 09:59:52 -0800435 mLocusId = b.mLocusId;
436
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800437 updateTimestamp();
438 }
439
Makoto Onuki440a1ea2016-07-20 14:21:18 -0700440 /**
441 * Extract extras from {@link #mIntents} and set them to {@link #mIntentPersistableExtrases}
442 * as {@link PersistableBundle}, and remove extras from the original intents.
443 */
444 private void fixUpIntentExtras() {
445 if (mIntents == null) {
446 mIntentPersistableExtrases = null;
447 return;
448 }
449 mIntentPersistableExtrases = new PersistableBundle[mIntents.length];
450 for (int i = 0; i < mIntents.length; i++) {
451 final Intent intent = mIntents[i];
452 final Bundle extras = intent.getExtras();
453 if (extras == null) {
454 mIntentPersistableExtrases[i] = null;
455 } else {
456 mIntentPersistableExtrases[i] = new PersistableBundle(extras);
457 intent.replaceExtras((Bundle) null);
458 }
459 }
460 }
461
462 private static ArraySet<String> cloneCategories(Set<String> source) {
Makoto Onukidf6da042016-06-16 09:51:40 -0700463 if (source == null) {
464 return null;
465 }
466 final ArraySet<String> ret = new ArraySet<>(source.size());
467 for (CharSequence s : source) {
468 if (!TextUtils.isEmpty(s)) {
469 ret.add(s.toString().intern());
470 }
471 }
472 return ret;
Makoto Onukib6d35232016-04-04 15:57:17 -0700473 }
474
Makoto Onuki440a1ea2016-07-20 14:21:18 -0700475 private static Intent[] cloneIntents(Intent[] intents) {
476 if (intents == null) {
477 return null;
478 }
479 final Intent[] ret = new Intent[intents.length];
480 for (int i = 0; i < ret.length; i++) {
481 if (intents[i] != null) {
482 ret[i] = new Intent(intents[i]);
483 }
484 }
485 return ret;
486 }
487
488 private static PersistableBundle[] clonePersistableBundle(PersistableBundle[] bundle) {
489 if (bundle == null) {
490 return null;
491 }
492 final PersistableBundle[] ret = new PersistableBundle[bundle.length];
493 for (int i = 0; i < ret.length; i++) {
494 if (bundle[i] != null) {
495 ret[i] = new PersistableBundle(bundle[i]);
496 }
497 }
498 return ret;
499 }
500
Mehdi Alizadeh14242af2018-12-20 20:11:35 -0800501 private static Person[] clonePersons(Person[] persons) {
502 if (persons == null) {
503 return null;
504 }
505 final Person[] ret = new Person[persons.length];
506 for (int i = 0; i < ret.length; i++) {
507 if (persons[i] != null) {
508 // Don't need to keep the icon, remove it to save space
509 ret[i] = persons[i].toBuilder().setIcon(null).build();
510 }
511 }
512 return ret;
513 }
514
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800515 /**
516 * Throws if any of the mandatory fields is not set.
517 *
518 * @hide
519 */
Makoto Onuki106ff7a2016-12-01 10:17:57 -0800520 public void enforceMandatoryFields(boolean forPinned) {
Makoto Onukie3ae7ec2016-03-29 15:45:25 -0700521 Preconditions.checkStringNotEmpty(mId, "Shortcut ID must be provided");
Makoto Onuki106ff7a2016-12-01 10:17:57 -0800522 if (!forPinned) {
Daulet Zhanguzina2044e12019-12-30 16:34:59 +0000523 Objects.requireNonNull(mActivity, "Activity must be provided");
Makoto Onuki106ff7a2016-12-01 10:17:57 -0800524 }
Makoto Onuki20c95f82016-05-11 16:51:01 -0700525 if (mTitle == null && mTitleResId == 0) {
Makoto Onukia1d38b32016-06-10 15:32:26 -0700526 throw new IllegalArgumentException("Short label must be provided");
Makoto Onuki20c95f82016-05-11 16:51:01 -0700527 }
Daulet Zhanguzina2044e12019-12-30 16:34:59 +0000528 Objects.requireNonNull(mIntents, "Shortcut Intent must be provided");
Makoto Onuki99302b52017-03-29 12:42:26 -0700529 Preconditions.checkArgument(mIntents.length > 0, "Shortcut Intent must be provided");
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800530 }
531
532 /**
533 * Copy constructor.
534 */
535 private ShortcutInfo(ShortcutInfo source, @CloneFlags int cloneFlags) {
Makoto Onukiabe84422016-04-07 09:41:19 -0700536 mUserId = source.mUserId;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800537 mId = source.mId;
538 mPackageName = source.mPackageName;
Makoto Onuki4d6b87f2016-06-17 13:47:40 -0700539 mActivity = source.mActivity;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800540 mFlags = source.mFlags;
541 mLastChangedTimestamp = source.mLastChangedTimestamp;
Makoto Onukia4f89b12017-10-05 10:37:55 -0700542 mDisabledReason = source.mDisabledReason;
Felipe Leme90205ef2019-03-05 09:59:52 -0800543 mLocusId = source.mLocusId;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800544
Makoto Onukib6d35232016-04-04 15:57:17 -0700545 // Just always keep it since it's cheep.
Makoto Onuki157b1622016-06-02 16:13:10 -0700546 mIconResId = source.mIconResId;
Makoto Onukib6d35232016-04-04 15:57:17 -0700547
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800548 if ((cloneFlags & CLONE_REMOVE_NON_KEY_INFO) == 0) {
Makoto Onuki55046222016-03-08 10:49:47 -0800549
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800550 if ((cloneFlags & CLONE_REMOVE_ICON) == 0) {
551 mIcon = source.mIcon;
Makoto Onuki7a6a05f2016-03-10 17:01:08 -0800552 mBitmapPath = source.mBitmapPath;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800553 }
554
555 mTitle = source.mTitle;
Makoto Onuki20c95f82016-05-11 16:51:01 -0700556 mTitleResId = source.mTitleResId;
Makoto Onukie3ae7ec2016-03-29 15:45:25 -0700557 mText = source.mText;
Makoto Onuki20c95f82016-05-11 16:51:01 -0700558 mTextResId = source.mTextResId;
559 mDisabledMessage = source.mDisabledMessage;
560 mDisabledMessageResId = source.mDisabledMessageResId;
Makoto Onukidf6da042016-06-16 09:51:40 -0700561 mCategories = cloneCategories(source.mCategories);
Mehdi Alizadehc6096022019-05-27 12:17:36 -0700562 if ((cloneFlags & CLONE_REMOVE_PERSON) == 0) {
563 mPersons = clonePersons(source.mPersons);
564 }
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800565 if ((cloneFlags & CLONE_REMOVE_INTENT) == 0) {
Makoto Onuki440a1ea2016-07-20 14:21:18 -0700566 mIntents = cloneIntents(source.mIntents);
567 mIntentPersistableExtrases =
568 clonePersistableBundle(source.mIntentPersistableExtrases);
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800569 }
Makoto Onuki20c95f82016-05-11 16:51:01 -0700570 mRank = source.mRank;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800571 mExtras = source.mExtras;
Makoto Onuki157b1622016-06-02 16:13:10 -0700572
573 if ((cloneFlags & CLONE_REMOVE_RES_NAMES) == 0) {
574 mTitleResName = source.mTitleResName;
575 mTextResName = source.mTextResName;
576 mDisabledMessageResName = source.mDisabledMessageResName;
577 mIconResName = source.mIconResName;
578 }
Makoto Onuki55046222016-03-08 10:49:47 -0800579 } else {
580 // Set this bit.
581 mFlags |= FLAG_KEY_FIELDS_ONLY;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800582 }
583 }
584
Makoto Onuki157b1622016-06-02 16:13:10 -0700585 /**
586 * Load a string resource from the publisher app.
587 *
588 * @param resId resource ID
589 * @param defValue default value to be returned when the specified resource isn't found.
590 */
591 private CharSequence getResourceString(Resources res, int resId, CharSequence defValue) {
592 try {
593 return res.getString(resId);
594 } catch (NotFoundException e) {
595 Log.e(TAG, "Resource for ID=" + resId + " not found in package " + mPackageName);
596 return defValue;
597 }
598 }
599
600 /**
601 * Load the string resources for the text fields and set them to the actual value fields.
602 * This will set {@link #FLAG_STRINGS_RESOLVED}.
603 *
604 * @param res {@link Resources} for the publisher. Must have been loaded with
605 * {@link PackageManager#getResourcesForApplicationAsUser}.
606 *
607 * @hide
608 */
609 public void resolveResourceStrings(@NonNull Resources res) {
Makoto Onuki20c95f82016-05-11 16:51:01 -0700610 mFlags |= FLAG_STRINGS_RESOLVED;
611
612 if ((mTitleResId == 0) && (mTextResId == 0) && (mDisabledMessageResId == 0)) {
613 return; // Bail early.
614 }
Makoto Onuki20c95f82016-05-11 16:51:01 -0700615
616 if (mTitleResId != 0) {
Makoto Onuki157b1622016-06-02 16:13:10 -0700617 mTitle = getResourceString(res, mTitleResId, mTitle);
Makoto Onuki20c95f82016-05-11 16:51:01 -0700618 }
619 if (mTextResId != 0) {
Makoto Onuki157b1622016-06-02 16:13:10 -0700620 mText = getResourceString(res, mTextResId, mText);
Makoto Onuki20c95f82016-05-11 16:51:01 -0700621 }
622 if (mDisabledMessageResId != 0) {
Makoto Onuki157b1622016-06-02 16:13:10 -0700623 mDisabledMessage = getResourceString(res, mDisabledMessageResId, mDisabledMessage);
Makoto Onuki20c95f82016-05-11 16:51:01 -0700624 }
625 }
626
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800627 /**
Makoto Onuki157b1622016-06-02 16:13:10 -0700628 * Look up resource name for a given resource ID.
629 *
630 * @return a simple resource name (e.g. "text_1") when {@code withType} is false, or with the
631 * type (e.g. "string/text_1").
632 *
633 * @hide
634 */
635 @VisibleForTesting
636 public static String lookUpResourceName(@NonNull Resources res, int resId, boolean withType,
637 @NonNull String packageName) {
638 if (resId == 0) {
639 return null;
640 }
641 try {
642 final String fullName = res.getResourceName(resId);
643
644 if (ANDROID_PACKAGE_NAME.equals(getResourcePackageName(fullName))) {
645 // If it's a framework resource, the value won't change, so just return the ID
646 // value as a string.
647 return String.valueOf(resId);
648 }
649 return withType ? getResourceTypeAndEntryName(fullName)
650 : getResourceEntryName(fullName);
651 } catch (NotFoundException e) {
652 Log.e(TAG, "Resource name for ID=" + resId + " not found in package " + packageName
653 + ". Resource IDs may change when the application is upgraded, and the system"
654 + " may not be able to find the correct resource.");
655 return null;
656 }
657 }
658
659 /**
660 * Extract the package name from a fully-donated resource name.
661 * e.g. "com.android.app1:drawable/icon1" -> "com.android.app1"
662 * @hide
663 */
664 @VisibleForTesting
665 public static String getResourcePackageName(@NonNull String fullResourceName) {
666 final int p1 = fullResourceName.indexOf(':');
667 if (p1 < 0) {
668 return null;
669 }
670 return fullResourceName.substring(0, p1);
671 }
672
673 /**
674 * Extract the type name from a fully-donated resource name.
675 * e.g. "com.android.app1:drawable/icon1" -> "drawable"
676 * @hide
677 */
678 @VisibleForTesting
679 public static String getResourceTypeName(@NonNull String fullResourceName) {
680 final int p1 = fullResourceName.indexOf(':');
681 if (p1 < 0) {
682 return null;
683 }
684 final int p2 = fullResourceName.indexOf('/', p1 + 1);
685 if (p2 < 0) {
686 return null;
687 }
688 return fullResourceName.substring(p1 + 1, p2);
689 }
690
691 /**
692 * Extract the type name + the entry name from a fully-donated resource name.
693 * e.g. "com.android.app1:drawable/icon1" -> "drawable/icon1"
694 * @hide
695 */
696 @VisibleForTesting
697 public static String getResourceTypeAndEntryName(@NonNull String fullResourceName) {
698 final int p1 = fullResourceName.indexOf(':');
699 if (p1 < 0) {
700 return null;
701 }
702 return fullResourceName.substring(p1 + 1);
703 }
704
705 /**
706 * Extract the entry name from a fully-donated resource name.
707 * e.g. "com.android.app1:drawable/icon1" -> "icon1"
708 * @hide
709 */
710 @VisibleForTesting
711 public static String getResourceEntryName(@NonNull String fullResourceName) {
712 final int p1 = fullResourceName.indexOf('/');
713 if (p1 < 0) {
714 return null;
715 }
716 return fullResourceName.substring(p1 + 1);
717 }
718
719 /**
720 * Return the resource ID for a given resource ID.
721 *
722 * Basically its' a wrapper over {@link Resources#getIdentifier(String, String, String)}, except
723 * if {@code resourceName} is an integer then it'll just return its value. (Which also the
724 * aforementioned method would do internally, but not documented, so doing here explicitly.)
725 *
726 * @param res {@link Resources} for the publisher. Must have been loaded with
727 * {@link PackageManager#getResourcesForApplicationAsUser}.
728 *
729 * @hide
730 */
731 @VisibleForTesting
732 public static int lookUpResourceId(@NonNull Resources res, @Nullable String resourceName,
733 @Nullable String resourceType, String packageName) {
734 if (resourceName == null) {
735 return 0;
736 }
737 try {
738 try {
739 // It the name can be parsed as an integer, just use it.
740 return Integer.parseInt(resourceName);
741 } catch (NumberFormatException ignore) {
742 }
743
744 return res.getIdentifier(resourceName, resourceType, packageName);
745 } catch (NotFoundException e) {
746 Log.e(TAG, "Resource ID for name=" + resourceName + " not found in package "
747 + packageName);
748 return 0;
749 }
750 }
751
752 /**
753 * Look up resource names from the resource IDs for the icon res and the text fields, and fill
754 * in the resource name fields.
755 *
756 * @param res {@link Resources} for the publisher. Must have been loaded with
757 * {@link PackageManager#getResourcesForApplicationAsUser}.
758 *
759 * @hide
760 */
761 public void lookupAndFillInResourceNames(@NonNull Resources res) {
762 if ((mTitleResId == 0) && (mTextResId == 0) && (mDisabledMessageResId == 0)
763 && (mIconResId == 0)) {
764 return; // Bail early.
765 }
766
767 // We don't need types for strings because their types are always "string".
768 mTitleResName = lookUpResourceName(res, mTitleResId, /*withType=*/ false, mPackageName);
769 mTextResName = lookUpResourceName(res, mTextResId, /*withType=*/ false, mPackageName);
770 mDisabledMessageResName = lookUpResourceName(res, mDisabledMessageResId,
771 /*withType=*/ false, mPackageName);
772
773 // But icons have multiple possible types, so include the type.
774 mIconResName = lookUpResourceName(res, mIconResId, /*withType=*/ true, mPackageName);
775 }
776
777 /**
778 * Look up resource IDs from the resource names for the icon res and the text fields, and fill
779 * in the resource ID fields.
780 *
781 * This is called when an app is updated.
782 *
783 * @hide
784 */
785 public void lookupAndFillInResourceIds(@NonNull Resources res) {
786 if ((mTitleResName == null) && (mTextResName == null) && (mDisabledMessageResName == null)
787 && (mIconResName == null)) {
788 return; // Bail early.
789 }
790
791 mTitleResId = lookUpResourceId(res, mTitleResName, RES_TYPE_STRING, mPackageName);
792 mTextResId = lookUpResourceId(res, mTextResName, RES_TYPE_STRING, mPackageName);
793 mDisabledMessageResId = lookUpResourceId(res, mDisabledMessageResName, RES_TYPE_STRING,
794 mPackageName);
795
796 // mIconResName already contains the type, so the third argument is not needed.
797 mIconResId = lookUpResourceId(res, mIconResName, null, mPackageName);
798 }
799
800 /**
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800801 * Copy a {@link ShortcutInfo}, optionally removing fields.
802 * @hide
803 */
804 public ShortcutInfo clone(@CloneFlags int cloneFlags) {
805 return new ShortcutInfo(this, cloneFlags);
806 }
807
808 /**
Makoto Onuki22fcc682016-05-17 14:52:19 -0700809 * @hide
Makoto Onukia4f89b12017-10-05 10:37:55 -0700810 *
811 * @isUpdating set true if it's "update", as opposed to "replace".
Makoto Onuki22fcc682016-05-17 14:52:19 -0700812 */
Makoto Onukia4f89b12017-10-05 10:37:55 -0700813 public void ensureUpdatableWith(ShortcutInfo source, boolean isUpdating) {
814 if (isUpdating) {
815 Preconditions.checkState(isVisibleToPublisher(),
816 "[Framework BUG] Invisible shortcuts can't be updated");
817 }
Makoto Onuki22fcc682016-05-17 14:52:19 -0700818 Preconditions.checkState(mUserId == source.mUserId, "Owner User ID must match");
819 Preconditions.checkState(mId.equals(source.mId), "ID must match");
820 Preconditions.checkState(mPackageName.equals(source.mPackageName),
821 "Package name must match");
Makoto Onukia4f89b12017-10-05 10:37:55 -0700822
823 if (isVisibleToPublisher()) {
824 // Don't do this check for restore-blocked shortcuts.
825 Preconditions.checkState(!isImmutable(), "Target ShortcutInfo is immutable");
826 }
Makoto Onuki22fcc682016-05-17 14:52:19 -0700827 }
828
829 /**
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800830 * Copy non-null/zero fields from another {@link ShortcutInfo}. Only "public" information
Makoto Onuki9e1f5592016-06-08 12:30:23 -0700831 * will be overwritten. The timestamp will *not* be updated to be consistent with other
832 * setters (and also the clock is not injectable in this file).
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800833 *
834 * - Flags will not change
835 * - mBitmapPath will not change
836 * - Current time will be set to timestamp
837 *
Makoto Onuki22fcc682016-05-17 14:52:19 -0700838 * @throws IllegalStateException if source is not compatible.
839 *
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800840 * @hide
841 */
842 public void copyNonNullFieldsFrom(ShortcutInfo source) {
Makoto Onukia4f89b12017-10-05 10:37:55 -0700843 ensureUpdatableWith(source, /*isUpdating=*/ true);
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800844
Makoto Onuki22fcc682016-05-17 14:52:19 -0700845 if (source.mActivity != null) {
846 mActivity = source.mActivity;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800847 }
848
849 if (source.mIcon != null) {
850 mIcon = source.mIcon;
Makoto Onuki157b1622016-06-02 16:13:10 -0700851
852 mIconResId = 0;
853 mIconResName = null;
854 mBitmapPath = null;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800855 }
856 if (source.mTitle != null) {
857 mTitle = source.mTitle;
Makoto Onuki20c95f82016-05-11 16:51:01 -0700858 mTitleResId = 0;
Makoto Onuki157b1622016-06-02 16:13:10 -0700859 mTitleResName = null;
Makoto Onuki20c95f82016-05-11 16:51:01 -0700860 } else if (source.mTitleResId != 0) {
861 mTitle = null;
Makoto Onukieddbfec2016-05-31 17:04:34 -0700862 mTitleResId = source.mTitleResId;
Makoto Onuki157b1622016-06-02 16:13:10 -0700863 mTitleResName = null;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800864 }
Makoto Onuki157b1622016-06-02 16:13:10 -0700865
Makoto Onukie3ae7ec2016-03-29 15:45:25 -0700866 if (source.mText != null) {
867 mText = source.mText;
Makoto Onuki20c95f82016-05-11 16:51:01 -0700868 mTextResId = 0;
Makoto Onuki157b1622016-06-02 16:13:10 -0700869 mTextResName = null;
Makoto Onuki20c95f82016-05-11 16:51:01 -0700870 } else if (source.mTextResId != 0) {
871 mText = null;
872 mTextResId = source.mTextResId;
Makoto Onuki157b1622016-06-02 16:13:10 -0700873 mTextResName = null;
Makoto Onuki20c95f82016-05-11 16:51:01 -0700874 }
875 if (source.mDisabledMessage != null) {
876 mDisabledMessage = source.mDisabledMessage;
877 mDisabledMessageResId = 0;
Makoto Onuki157b1622016-06-02 16:13:10 -0700878 mDisabledMessageResName = null;
Makoto Onuki20c95f82016-05-11 16:51:01 -0700879 } else if (source.mDisabledMessageResId != 0) {
880 mDisabledMessage = null;
881 mDisabledMessageResId = source.mDisabledMessageResId;
Makoto Onuki157b1622016-06-02 16:13:10 -0700882 mDisabledMessageResName = null;
Makoto Onukie3ae7ec2016-03-29 15:45:25 -0700883 }
Makoto Onukib6d35232016-04-04 15:57:17 -0700884 if (source.mCategories != null) {
Makoto Onukidf6da042016-06-16 09:51:40 -0700885 mCategories = cloneCategories(source.mCategories);
Makoto Onukib6d35232016-04-04 15:57:17 -0700886 }
Mehdi Alizadeh14242af2018-12-20 20:11:35 -0800887 if (source.mPersons != null) {
888 mPersons = clonePersons(source.mPersons);
889 }
Makoto Onuki440a1ea2016-07-20 14:21:18 -0700890 if (source.mIntents != null) {
891 mIntents = cloneIntents(source.mIntents);
892 mIntentPersistableExtrases =
893 clonePersistableBundle(source.mIntentPersistableExtrases);
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800894 }
Makoto Onuki9e1f5592016-06-08 12:30:23 -0700895 if (source.mRank != RANK_NOT_SET) {
Makoto Onuki20c95f82016-05-11 16:51:01 -0700896 mRank = source.mRank;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800897 }
898 if (source.mExtras != null) {
899 mExtras = source.mExtras;
900 }
Felipe Leme90205ef2019-03-05 09:59:52 -0800901
902 if (source.mLocusId != null) {
903 mLocusId = source.mLocusId;
904 }
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800905 }
906
907 /**
Makoto Onuki55046222016-03-08 10:49:47 -0800908 * @hide
909 */
910 public static Icon validateIcon(Icon icon) {
911 switch (icon.getType()) {
912 case Icon.TYPE_RESOURCE:
913 case Icon.TYPE_BITMAP:
Hyunyoung Songe4179e22017-03-01 12:51:26 -0800914 case Icon.TYPE_ADAPTIVE_BITMAP:
Makoto Onuki55046222016-03-08 10:49:47 -0800915 break; // OK
Makoto Onuki55046222016-03-08 10:49:47 -0800916 default:
917 throw getInvalidIconException();
918 }
919 if (icon.hasTint()) {
Makoto Onuki55046222016-03-08 10:49:47 -0800920 throw new IllegalArgumentException("Icons with tints are not supported");
921 }
922
923 return icon;
924 }
925
926 /** @hide */
927 public static IllegalArgumentException getInvalidIconException() {
928 return new IllegalArgumentException("Unsupported icon type:"
Makoto Onukia97256b2016-07-15 13:23:54 -0700929 +" only the bitmap and resource types are supported");
Makoto Onuki55046222016-03-08 10:49:47 -0800930 }
931
932 /**
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800933 * Builder class for {@link ShortcutInfo} objects.
Makoto Onuki4a910962016-07-07 13:57:34 -0700934 *
935 * @see ShortcutManager
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800936 */
937 public static class Builder {
938 private final Context mContext;
939
940 private String mId;
941
Makoto Onuki22fcc682016-05-17 14:52:19 -0700942 private ComponentName mActivity;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800943
944 private Icon mIcon;
945
Makoto Onuki20c95f82016-05-11 16:51:01 -0700946 private int mTitleResId;
947
Makoto Onuki22fcc682016-05-17 14:52:19 -0700948 private CharSequence mTitle;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800949
Makoto Onuki20c95f82016-05-11 16:51:01 -0700950 private int mTextResId;
951
Makoto Onuki22fcc682016-05-17 14:52:19 -0700952 private CharSequence mText;
Makoto Onukie3ae7ec2016-03-29 15:45:25 -0700953
Makoto Onuki20c95f82016-05-11 16:51:01 -0700954 private int mDisabledMessageResId;
955
Makoto Onuki22fcc682016-05-17 14:52:19 -0700956 private CharSequence mDisabledMessage;
Makoto Onuki20c95f82016-05-11 16:51:01 -0700957
Makoto Onukibe73a802016-04-15 14:46:35 -0700958 private Set<String> mCategories;
Makoto Onukib6d35232016-04-04 15:57:17 -0700959
Makoto Onuki440a1ea2016-07-20 14:21:18 -0700960 private Intent[] mIntents;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800961
Mehdi Alizadeh14242af2018-12-20 20:11:35 -0800962 private Person[] mPersons;
963
964 private boolean mIsLongLived;
965
Makoto Onuki9e1f5592016-06-08 12:30:23 -0700966 private int mRank = RANK_NOT_SET;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800967
968 private PersistableBundle mExtras;
969
Felipe Leme90205ef2019-03-05 09:59:52 -0800970 private LocusId mLocusId;
971
Makoto Onukib5a012f2016-06-21 11:13:53 -0700972 /**
Makoto Onuki598aca42016-07-06 16:05:03 -0700973 * Old style constructor.
974 * @hide
Makoto Onukib5a012f2016-06-21 11:13:53 -0700975 */
976 @Deprecated
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800977 public Builder(Context context) {
978 mContext = context;
979 }
980
981 /**
Makoto Onuki598aca42016-07-06 16:05:03 -0700982 * Used with the old style constructor, kept for unit tests.
983 * @hide
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800984 */
985 @NonNull
Makoto Onukib5a012f2016-06-21 11:13:53 -0700986 @Deprecated
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800987 public Builder setId(@NonNull String id) {
Makoto Onukib08790c2016-06-23 14:05:46 -0700988 mId = Preconditions.checkStringNotEmpty(id, "id cannot be empty");
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800989 return this;
990 }
991
992 /**
Makoto Onukib5a012f2016-06-21 11:13:53 -0700993 * Constructor.
994 *
995 * @param context Client context.
996 * @param id ID of the shortcut.
997 */
998 public Builder(Context context, String id) {
999 mContext = context;
Makoto Onukib08790c2016-06-23 14:05:46 -07001000 mId = Preconditions.checkStringNotEmpty(id, "id cannot be empty");
Makoto Onukib5a012f2016-06-21 11:13:53 -07001001 }
1002
1003 /**
Felipe Leme90205ef2019-03-05 09:59:52 -08001004 * Sets the {@link LocusId} associated with this shortcut.
1005 *
1006 * <p>This method should be called when the {@link LocusId} is used in other places (such
1007 * as {@link Notification} and {@link ContentCaptureContext}) so the device's intelligence
1008 * services can correlate them.
1009 */
1010 @NonNull
1011 public Builder setLocusId(@NonNull LocusId locusId) {
Daulet Zhanguzina2044e12019-12-30 16:34:59 +00001012 mLocusId = Objects.requireNonNull(locusId, "locusId cannot be null");
Felipe Leme90205ef2019-03-05 09:59:52 -08001013 return this;
1014 }
1015
1016 /**
Makoto Onuki4a910962016-07-07 13:57:34 -07001017 * Sets the target activity. A shortcut will be shown along with this activity's icon
1018 * on the launcher.
Makoto Onukib5a012f2016-06-21 11:13:53 -07001019 *
Makoto Onukife9c9662016-07-25 15:12:23 -07001020 * When selecting a target activity, keep the following in mind:
Makoto Onuki4a910962016-07-07 13:57:34 -07001021 * <ul>
Makoto Onukife9c9662016-07-25 15:12:23 -07001022 * <li>All dynamic shortcuts must have a target activity. When a shortcut with no target
1023 * activity is published using
1024 * {@link ShortcutManager#addDynamicShortcuts(List)} or
1025 * {@link ShortcutManager#setDynamicShortcuts(List)},
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001026 * the first main activity defined in the app's <code>AndroidManifest.xml</code>
Makoto Onukife9c9662016-07-25 15:12:23 -07001027 * file is used.
1028 *
1029 * <li>Only "main" activities&mdash;ones that define the {@link Intent#ACTION_MAIN}
1030 * and {@link Intent#CATEGORY_LAUNCHER} intent filters&mdash;can be target
Makoto Onuki4a910962016-07-07 13:57:34 -07001031 * activities.
1032 *
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001033 * <li>By default, the first main activity defined in the app's manifest is
Makoto Onukife9c9662016-07-25 15:12:23 -07001034 * the target activity.
Makoto Onuki4d36b3a2016-04-27 12:00:17 -07001035 *
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001036 * <li>A target activity must belong to the publisher app.
Makoto Onuki4a910962016-07-07 13:57:34 -07001037 * </ul>
Makoto Onuki4d36b3a2016-04-27 12:00:17 -07001038 *
Makoto Onuki4a910962016-07-07 13:57:34 -07001039 * @see ShortcutInfo#getActivity()
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001040 */
1041 @NonNull
Makoto Onuki22fcc682016-05-17 14:52:19 -07001042 public Builder setActivity(@NonNull ComponentName activity) {
Daulet Zhanguzina2044e12019-12-30 16:34:59 +00001043 mActivity = Objects.requireNonNull(activity, "activity cannot be null");
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001044 return this;
1045 }
1046
1047 /**
Makoto Onuki4a910962016-07-07 13:57:34 -07001048 * Sets an icon of a shortcut.
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001049 *
Makoto Onuki4a910962016-07-07 13:57:34 -07001050 * <p>Icons are not available on {@link ShortcutInfo} instances
1051 * returned by {@link ShortcutManager} or {@link LauncherApps}. The default launcher
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001052 * app can use {@link LauncherApps#getShortcutIconDrawable(ShortcutInfo, int)}
Makoto Onukib5a012f2016-06-21 11:13:53 -07001053 * or {@link LauncherApps#getShortcutBadgedIconDrawable(ShortcutInfo, int)} to fetch
1054 * shortcut icons.
Makoto Onuki4a910962016-07-07 13:57:34 -07001055 *
1056 * <p>Tints set with {@link Icon#setTint} or {@link Icon#setTintList} are not supported
1057 * and will be ignored.
1058 *
Hyunyoung Songf281e7a2017-02-13 10:57:42 -08001059 * <p>Only icons created with {@link Icon#createWithBitmap(Bitmap)},
Hyunyoung Songe4179e22017-03-01 12:51:26 -08001060 * {@link Icon#createWithAdaptiveBitmap(Bitmap)}
Hyunyoung Songf281e7a2017-02-13 10:57:42 -08001061 * and {@link Icon#createWithResource} are supported.
Makoto Onukife9c9662016-07-25 15:12:23 -07001062 * Other types, such as URI-based icons, are not supported.
Makoto Onuki4a910962016-07-07 13:57:34 -07001063 *
1064 * @see LauncherApps#getShortcutIconDrawable(ShortcutInfo, int)
1065 * @see LauncherApps#getShortcutBadgedIconDrawable(ShortcutInfo, int)
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001066 */
1067 @NonNull
1068 public Builder setIcon(Icon icon) {
Makoto Onuki55046222016-03-08 10:49:47 -08001069 mIcon = validateIcon(icon);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001070 return this;
1071 }
1072
Makoto Onukieddbfec2016-05-31 17:04:34 -07001073 /**
1074 * @hide We don't support resource strings for dynamic shortcuts for now. (But unit tests
1075 * use it.)
1076 */
Makoto Onukib5a012f2016-06-21 11:13:53 -07001077 @Deprecated
Makoto Onukieddbfec2016-05-31 17:04:34 -07001078 public Builder setShortLabelResId(int shortLabelResId) {
1079 Preconditions.checkState(mTitle == null, "shortLabel already set");
1080 mTitleResId = shortLabelResId;
Makoto Onuki20c95f82016-05-11 16:51:01 -07001081 return this;
1082 }
1083
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001084 /**
Makoto Onukib5a012f2016-06-21 11:13:53 -07001085 * Sets the short title of a shortcut.
1086 *
Makoto Onuki4a910962016-07-07 13:57:34 -07001087 * <p>This is a mandatory field when publishing a new shortcut with
1088 * {@link ShortcutManager#addDynamicShortcuts(List)} or
1089 * {@link ShortcutManager#setDynamicShortcuts(List)}.
Makoto Onuki0e65d362016-03-29 14:46:50 -07001090 *
Makoto Onukife9c9662016-07-25 15:12:23 -07001091 * <p>This field is intended to be a concise description of a shortcut.
Makoto Onuki4a910962016-07-07 13:57:34 -07001092 *
Makoto Onukife9c9662016-07-25 15:12:23 -07001093 * <p>The recommended maximum length is 10 characters.
Makoto Onuki4a910962016-07-07 13:57:34 -07001094 *
1095 * @see ShortcutInfo#getShortLabel()
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001096 */
1097 @NonNull
Makoto Onukidf6da042016-06-16 09:51:40 -07001098 public Builder setShortLabel(@NonNull CharSequence shortLabel) {
Makoto Onukieddbfec2016-05-31 17:04:34 -07001099 Preconditions.checkState(mTitleResId == 0, "shortLabelResId already set");
Makoto Onukib08790c2016-06-23 14:05:46 -07001100 mTitle = Preconditions.checkStringNotEmpty(shortLabel, "shortLabel cannot be empty");
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001101 return this;
1102 }
1103
Makoto Onukieddbfec2016-05-31 17:04:34 -07001104 /**
1105 * @hide We don't support resource strings for dynamic shortcuts for now. (But unit tests
1106 * use it.)
1107 */
Makoto Onukib5a012f2016-06-21 11:13:53 -07001108 @Deprecated
Makoto Onukieddbfec2016-05-31 17:04:34 -07001109 public Builder setLongLabelResId(int longLabelResId) {
1110 Preconditions.checkState(mText == null, "longLabel already set");
1111 mTextResId = longLabelResId;
Makoto Onuki20c95f82016-05-11 16:51:01 -07001112 return this;
1113 }
1114
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001115 /**
Makoto Onukib5a012f2016-06-21 11:13:53 -07001116 * Sets the text of a shortcut.
Makoto Onuki0e65d362016-03-29 14:46:50 -07001117 *
Makoto Onukieddbfec2016-05-31 17:04:34 -07001118 * <p>This field is intended to be more descriptive than the shortcut title. The launcher
Makoto Onuki4a910962016-07-07 13:57:34 -07001119 * shows this instead of the short title when it has enough space.
1120 *
Makoto Onukife9c9662016-07-25 15:12:23 -07001121 * <p>The recommend maximum length is 25 characters.
Makoto Onuki4a910962016-07-07 13:57:34 -07001122 *
1123 * @see ShortcutInfo#getLongLabel()
Makoto Onukie3ae7ec2016-03-29 15:45:25 -07001124 */
1125 @NonNull
Makoto Onukidf6da042016-06-16 09:51:40 -07001126 public Builder setLongLabel(@NonNull CharSequence longLabel) {
Makoto Onukieddbfec2016-05-31 17:04:34 -07001127 Preconditions.checkState(mTextResId == 0, "longLabelResId already set");
Makoto Onukib08790c2016-06-23 14:05:46 -07001128 mText = Preconditions.checkStringNotEmpty(longLabel, "longLabel cannot be empty");
Makoto Onukie3ae7ec2016-03-29 15:45:25 -07001129 return this;
1130 }
1131
Makoto Onukieddbfec2016-05-31 17:04:34 -07001132 /** @hide -- old signature, the internal code still uses it. */
Makoto Onukib5a012f2016-06-21 11:13:53 -07001133 @Deprecated
Makoto Onukidf6da042016-06-16 09:51:40 -07001134 public Builder setTitle(@NonNull CharSequence value) {
Makoto Onukieddbfec2016-05-31 17:04:34 -07001135 return setShortLabel(value);
1136 }
1137
1138 /** @hide -- old signature, the internal code still uses it. */
Makoto Onukib5a012f2016-06-21 11:13:53 -07001139 @Deprecated
Makoto Onukieddbfec2016-05-31 17:04:34 -07001140 public Builder setTitleResId(int value) {
1141 return setShortLabelResId(value);
1142 }
1143
1144 /** @hide -- old signature, the internal code still uses it. */
Makoto Onukib5a012f2016-06-21 11:13:53 -07001145 @Deprecated
Makoto Onukidf6da042016-06-16 09:51:40 -07001146 public Builder setText(@NonNull CharSequence value) {
Makoto Onukieddbfec2016-05-31 17:04:34 -07001147 return setLongLabel(value);
1148 }
1149
1150 /** @hide -- old signature, the internal code still uses it. */
Makoto Onukib5a012f2016-06-21 11:13:53 -07001151 @Deprecated
Makoto Onukieddbfec2016-05-31 17:04:34 -07001152 public Builder setTextResId(int value) {
1153 return setLongLabelResId(value);
1154 }
1155
1156 /**
1157 * @hide We don't support resource strings for dynamic shortcuts for now. (But unit tests
1158 * use it.)
1159 */
Makoto Onukib5a012f2016-06-21 11:13:53 -07001160 @Deprecated
Makoto Onuki20c95f82016-05-11 16:51:01 -07001161 public Builder setDisabledMessageResId(int disabledMessageResId) {
1162 Preconditions.checkState(mDisabledMessage == null, "disabledMessage already set");
1163 mDisabledMessageResId = disabledMessageResId;
1164 return this;
1165 }
1166
Makoto Onuki4a910962016-07-07 13:57:34 -07001167 /**
Makoto Onukife9c9662016-07-25 15:12:23 -07001168 * Sets the message that should be shown when the user attempts to start a shortcut that
1169 * is disabled.
Makoto Onuki4a910962016-07-07 13:57:34 -07001170 *
1171 * @see ShortcutInfo#getDisabledMessage()
1172 */
Makoto Onuki20c95f82016-05-11 16:51:01 -07001173 @NonNull
Makoto Onukidf6da042016-06-16 09:51:40 -07001174 public Builder setDisabledMessage(@NonNull CharSequence disabledMessage) {
Makoto Onuki20c95f82016-05-11 16:51:01 -07001175 Preconditions.checkState(
1176 mDisabledMessageResId == 0, "disabledMessageResId already set");
1177 mDisabledMessage =
Makoto Onukib08790c2016-06-23 14:05:46 -07001178 Preconditions.checkStringNotEmpty(disabledMessage,
1179 "disabledMessage cannot be empty");
Makoto Onuki20c95f82016-05-11 16:51:01 -07001180 return this;
1181 }
1182
Makoto Onukie3ae7ec2016-03-29 15:45:25 -07001183 /**
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001184 * Sets categories for a shortcut. Launcher apps may use this information to
1185 * categorize shortcuts.
Makoto Onukib6d35232016-04-04 15:57:17 -07001186 *
1187 * @see #SHORTCUT_CATEGORY_CONVERSATION
Makoto Onuki4a910962016-07-07 13:57:34 -07001188 * @see ShortcutInfo#getCategories()
Makoto Onukib6d35232016-04-04 15:57:17 -07001189 */
1190 @NonNull
Makoto Onukibe73a802016-04-15 14:46:35 -07001191 public Builder setCategories(Set<String> categories) {
Makoto Onukib6d35232016-04-04 15:57:17 -07001192 mCategories = categories;
1193 return this;
1194 }
1195
1196 /**
Makoto Onuki0eed4412016-07-21 11:21:59 -07001197 * Sets the intent of a shortcut. Alternatively, {@link #setIntents(Intent[])} can be used
1198 * to launch an activity with other activities in the back stack.
Makoto Onuki4a910962016-07-07 13:57:34 -07001199 *
1200 * <p>This is a mandatory field when publishing a new shortcut with
1201 * {@link ShortcutManager#addDynamicShortcuts(List)} or
1202 * {@link ShortcutManager#setDynamicShortcuts(List)}.
1203 *
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001204 * <p>A shortcut can launch any intent that the publisher app has permission to
Makoto Onukife9c9662016-07-25 15:12:23 -07001205 * launch. For example, a shortcut can launch an unexported activity within the publisher
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001206 * app. A shortcut intent doesn't have to point at the target activity.
Makoto Onuki4a910962016-07-07 13:57:34 -07001207 *
Makoto Onukife9c9662016-07-25 15:12:23 -07001208 * <p>The given {@code intent} can contain extras, but these extras must contain values
1209 * of primitive types in order for the system to persist these values.
Makoto Onuki4a910962016-07-07 13:57:34 -07001210 *
1211 * @see ShortcutInfo#getIntent()
Makoto Onuki440a1ea2016-07-20 14:21:18 -07001212 * @see #setIntents(Intent[])
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001213 */
1214 @NonNull
1215 public Builder setIntent(@NonNull Intent intent) {
Makoto Onuki440a1ea2016-07-20 14:21:18 -07001216 return setIntents(new Intent[]{intent});
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001217 }
1218
1219 /**
Makoto Onuki0eed4412016-07-21 11:21:59 -07001220 * Sets multiple intents instead of a single intent, in order to launch an activity with
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001221 * other activities in back stack. Use {@link TaskStackBuilder} to build intents. The
1222 * last element in the list represents the only intent that doesn't place an activity on
1223 * the back stack.
Makoto Onuki0eed4412016-07-21 11:21:59 -07001224 * See the {@link ShortcutManager} javadoc for details.
Makoto Onuki347a6bd2016-07-19 11:13:08 -07001225 *
1226 * @see Builder#setIntent(Intent)
1227 * @see ShortcutInfo#getIntents()
1228 * @see Context#startActivities(Intent[])
1229 * @see TaskStackBuilder
1230 */
1231 @NonNull
1232 public Builder setIntents(@NonNull Intent[] intents) {
Daulet Zhanguzina2044e12019-12-30 16:34:59 +00001233 Objects.requireNonNull(intents, "intents cannot be null");
1234 Objects.requireNonNull(intents.length, "intents cannot be empty");
Makoto Onuki440a1ea2016-07-20 14:21:18 -07001235 for (Intent intent : intents) {
Daulet Zhanguzina2044e12019-12-30 16:34:59 +00001236 Objects.requireNonNull(intent, "intents cannot contain null");
1237 Objects.requireNonNull(intent.getAction(), "intent's action must be set");
Makoto Onuki440a1ea2016-07-20 14:21:18 -07001238 }
1239 // Make sure always clone incoming intents.
1240 mIntents = cloneIntents(intents);
1241 return this;
Makoto Onuki347a6bd2016-07-19 11:13:08 -07001242 }
1243
1244 /**
Mehdi Alizadeh14242af2018-12-20 20:11:35 -08001245 * Add a person that is relevant to this shortcut. Alternatively,
1246 * {@link #setPersons(Person[])} can be used to add multiple persons to a shortcut.
1247 *
1248 * <p> This is an optional field, but the addition of person may cause this shortcut to
1249 * appear more prominently in the user interface (e.g. ShareSheet).
1250 *
1251 * <p> A person should usually contain a uri in order to benefit from the ranking boost.
1252 * However, even if no uri is provided, it's beneficial to provide people in the shortcut,
1253 * such that listeners and voice only devices can announce and handle them properly.
1254 *
1255 * @see Person
1256 * @see #setPersons(Person[])
1257 */
1258 @NonNull
1259 public Builder setPerson(@NonNull Person person) {
1260 return setPersons(new Person[]{person});
1261 }
1262
1263 /**
1264 * Sets multiple persons instead of a single person.
1265 *
1266 * @see Person
1267 * @see #setPerson(Person)
1268 */
1269 @NonNull
1270 public Builder setPersons(@NonNull Person[] persons) {
Daulet Zhanguzina2044e12019-12-30 16:34:59 +00001271 Objects.requireNonNull(persons, "persons cannot be null");
1272 Objects.requireNonNull(persons.length, "persons cannot be empty");
Mehdi Alizadeh14242af2018-12-20 20:11:35 -08001273 for (Person person : persons) {
Daulet Zhanguzina2044e12019-12-30 16:34:59 +00001274 Objects.requireNonNull(person, "persons cannot contain null");
Mehdi Alizadeh14242af2018-12-20 20:11:35 -08001275 }
1276 mPersons = clonePersons(persons);
1277 return this;
1278 }
1279
1280 /**
1281 * Sets if a shortcut would be valid even if it has been unpublished/invisible by the app
1282 * (as a dynamic or pinned shortcut). If it is long lived, it can be cached by various
1283 * system services even after it has been unpublished as a dynamic shortcut.
1284 */
1285 @NonNull
Mehdi Alizadeh3d2ff4c2019-03-13 15:45:03 -07001286 public Builder setLongLived(boolean londLived) {
1287 mIsLongLived = londLived;
Mehdi Alizadeh14242af2018-12-20 20:11:35 -08001288 return this;
1289 }
1290
1291 /**
Makoto Onuki9e1f5592016-06-08 12:30:23 -07001292 * "Rank" of a shortcut, which is a non-negative value that's used by the launcher app
1293 * to sort shortcuts.
Makoto Onuki4a910962016-07-07 13:57:34 -07001294 *
1295 * See {@link ShortcutInfo#getRank()} for details.
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001296 */
1297 @NonNull
Makoto Onuki20c95f82016-05-11 16:51:01 -07001298 public Builder setRank(int rank) {
Makoto Onuki9e1f5592016-06-08 12:30:23 -07001299 Preconditions.checkArgument((0 <= rank),
1300 "Rank cannot be negative or bigger than MAX_RANK");
Makoto Onuki20c95f82016-05-11 16:51:01 -07001301 mRank = rank;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001302 return this;
1303 }
1304
1305 /**
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001306 * Extras that the app can set for any purpose.
Makoto Onukib5a012f2016-06-21 11:13:53 -07001307 *
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001308 * <p>Apps can store arbitrary shortcut metadata in extras and retrieve the
Makoto Onukife9c9662016-07-25 15:12:23 -07001309 * metadata later using {@link ShortcutInfo#getExtras()}.
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001310 */
1311 @NonNull
1312 public Builder setExtras(@NonNull PersistableBundle extras) {
1313 mExtras = extras;
1314 return this;
1315 }
1316
Hakan Seyalioglu58fc95d2016-12-13 15:23:22 -08001317 /**
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001318 * Creates a {@link ShortcutInfo} instance.
1319 */
1320 @NonNull
1321 public ShortcutInfo build() {
1322 return new ShortcutInfo(this);
1323 }
1324 }
1325
1326 /**
Makoto Onuki4a910962016-07-07 13:57:34 -07001327 * Returns the ID of a shortcut.
1328 *
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001329 * <p>Shortcut IDs are unique within each publisher app and must be stable across
Makoto Onukife9c9662016-07-25 15:12:23 -07001330 * devices so that shortcuts will still be valid when restored on a different device.
1331 * See {@link ShortcutManager} for details.
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001332 */
1333 @NonNull
1334 public String getId() {
1335 return mId;
1336 }
1337
1338 /**
Felipe Leme90205ef2019-03-05 09:59:52 -08001339 * Gets the {@link LocusId} associated with this shortcut.
1340 *
1341 * <p>Used by the device's intelligence services to correlate objects (such as
1342 * {@link Notification} and {@link ContentCaptureContext}) that are correlated.
1343 */
1344 @Nullable
1345 public LocusId getLocusId() {
1346 return mLocusId;
1347 }
1348
1349 /**
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001350 * Return the package name of the publisher app.
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001351 */
1352 @NonNull
Makoto Onuki22fcc682016-05-17 14:52:19 -07001353 public String getPackage() {
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001354 return mPackageName;
1355 }
1356
1357 /**
Makoto Onuki4a910962016-07-07 13:57:34 -07001358 * Return the target activity.
Makoto Onuki4d36b3a2016-04-27 12:00:17 -07001359 *
Makoto Onukife9c9662016-07-25 15:12:23 -07001360 * <p>This has nothing to do with the activity that this shortcut will launch.
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001361 * Launcher apps should show the launcher icon for the returned activity alongside
Makoto Onukife9c9662016-07-25 15:12:23 -07001362 * this shortcut.
Makoto Onuki4d36b3a2016-04-27 12:00:17 -07001363 *
Makoto Onuki22fcc682016-05-17 14:52:19 -07001364 * @see Builder#setActivity
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001365 */
1366 @Nullable
Makoto Onuki22fcc682016-05-17 14:52:19 -07001367 public ComponentName getActivity() {
1368 return mActivity;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001369 }
1370
Makoto Onukib08790c2016-06-23 14:05:46 -07001371 /** @hide */
1372 public void setActivity(ComponentName activity) {
1373 mActivity = activity;
1374 }
1375
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001376 /**
Makoto Onuki4a910962016-07-07 13:57:34 -07001377 * Returns the shortcut icon.
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001378 *
1379 * @hide
1380 */
1381 @Nullable
Mathew Inwood8c854f82018-09-14 12:35:36 +01001382 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001383 public Icon getIcon() {
1384 return mIcon;
1385 }
1386
Makoto Onukieddbfec2016-05-31 17:04:34 -07001387 /** @hide -- old signature, the internal code still uses it. */
Makoto Onuki55046222016-03-08 10:49:47 -08001388 @Nullable
Makoto Onukib5a012f2016-06-21 11:13:53 -07001389 @Deprecated
Makoto Onuki22fcc682016-05-17 14:52:19 -07001390 public CharSequence getTitle() {
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001391 return mTitle;
1392 }
1393
Makoto Onukieddbfec2016-05-31 17:04:34 -07001394 /** @hide -- old signature, the internal code still uses it. */
Makoto Onukib5a012f2016-06-21 11:13:53 -07001395 @Deprecated
Makoto Onuki20c95f82016-05-11 16:51:01 -07001396 public int getTitleResId() {
1397 return mTitleResId;
1398 }
1399
Makoto Onukieddbfec2016-05-31 17:04:34 -07001400 /** @hide -- old signature, the internal code still uses it. */
1401 @Nullable
Makoto Onukib5a012f2016-06-21 11:13:53 -07001402 @Deprecated
Makoto Onukieddbfec2016-05-31 17:04:34 -07001403 public CharSequence getText() {
1404 return mText;
1405 }
1406
1407 /** @hide -- old signature, the internal code still uses it. */
Makoto Onukib5a012f2016-06-21 11:13:53 -07001408 @Deprecated
Makoto Onukieddbfec2016-05-31 17:04:34 -07001409 public int getTextResId() {
1410 return mTextResId;
1411 }
1412
1413 /**
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001414 * Return the short description of a shortcut.
Makoto Onukieddbfec2016-05-31 17:04:34 -07001415 *
Makoto Onuki4a910962016-07-07 13:57:34 -07001416 * @see Builder#setShortLabel(CharSequence)
Makoto Onukieddbfec2016-05-31 17:04:34 -07001417 */
1418 @Nullable
1419 public CharSequence getShortLabel() {
1420 return mTitle;
1421 }
1422
Makoto Onuki598aca42016-07-06 16:05:03 -07001423 /** @hide */
Makoto Onukieddbfec2016-05-31 17:04:34 -07001424 public int getShortLabelResourceId() {
1425 return mTitleResId;
1426 }
1427
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001428 /**
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001429 * Return the long description of a shortcut.
Makoto Onuki4a910962016-07-07 13:57:34 -07001430 *
1431 * @see Builder#setLongLabel(CharSequence)
Makoto Onukie3ae7ec2016-03-29 15:45:25 -07001432 */
1433 @Nullable
Makoto Onukieddbfec2016-05-31 17:04:34 -07001434 public CharSequence getLongLabel() {
Makoto Onukie3ae7ec2016-03-29 15:45:25 -07001435 return mText;
1436 }
1437
Makoto Onuki598aca42016-07-06 16:05:03 -07001438 /** @hide */
Makoto Onukieddbfec2016-05-31 17:04:34 -07001439 public int getLongLabelResourceId() {
Makoto Onuki20c95f82016-05-11 16:51:01 -07001440 return mTextResId;
1441 }
1442
1443 /**
Makoto Onukife9c9662016-07-25 15:12:23 -07001444 * Return the message that should be shown when the user attempts to start a shortcut
1445 * that is disabled.
Makoto Onuki4a910962016-07-07 13:57:34 -07001446 *
1447 * @see Builder#setDisabledMessage(CharSequence)
Makoto Onuki20c95f82016-05-11 16:51:01 -07001448 */
1449 @Nullable
Makoto Onuki22fcc682016-05-17 14:52:19 -07001450 public CharSequence getDisabledMessage() {
Makoto Onuki20c95f82016-05-11 16:51:01 -07001451 return mDisabledMessage;
1452 }
1453
Makoto Onuki598aca42016-07-06 16:05:03 -07001454 /** @hide */
Makoto Onukieddbfec2016-05-31 17:04:34 -07001455 public int getDisabledMessageResourceId() {
Makoto Onuki20c95f82016-05-11 16:51:01 -07001456 return mDisabledMessageResId;
1457 }
1458
Makoto Onukia4f89b12017-10-05 10:37:55 -07001459 /** @hide */
1460 public void setDisabledReason(@DisabledReason int reason) {
1461 mDisabledReason = reason;
1462 }
1463
1464 /**
1465 * Returns why a shortcut has been disabled.
1466 */
1467 @DisabledReason
1468 public int getDisabledReason() {
1469 return mDisabledReason;
1470 }
1471
Makoto Onukie3ae7ec2016-03-29 15:45:25 -07001472 /**
Makoto Onukife9c9662016-07-25 15:12:23 -07001473 * Return the shortcut's categories.
Makoto Onuki4a910962016-07-07 13:57:34 -07001474 *
1475 * @see Builder#setCategories(Set)
Makoto Onukib6d35232016-04-04 15:57:17 -07001476 */
1477 @Nullable
Makoto Onukibe73a802016-04-15 14:46:35 -07001478 public Set<String> getCategories() {
Makoto Onukib6d35232016-04-04 15:57:17 -07001479 return mCategories;
1480 }
1481
1482 /**
Makoto Onukife9c9662016-07-25 15:12:23 -07001483 * Returns the intent that is executed when the user selects this shortcut.
1484 * If setIntents() was used, then return the last intent in the array.
Makoto Onuki55046222016-03-08 10:49:47 -08001485 *
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001486 * <p>Launcher apps <b>cannot</b> see the intent. If a {@link ShortcutInfo} is
Makoto Onuki4a910962016-07-07 13:57:34 -07001487 * obtained via {@link LauncherApps}, then this method will always return null.
1488 * Launchers can only start a shortcut intent with {@link LauncherApps#startShortcut}.
Makoto Onuki4d36b3a2016-04-27 12:00:17 -07001489 *
Makoto Onuki4a910962016-07-07 13:57:34 -07001490 * @see Builder#setIntent(Intent)
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001491 */
Makoto Onuki55046222016-03-08 10:49:47 -08001492 @Nullable
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001493 public Intent getIntent() {
Makoto Onuki440a1ea2016-07-20 14:21:18 -07001494 if (mIntents == null || mIntents.length == 0) {
Makoto Onuki55046222016-03-08 10:49:47 -08001495 return null;
1496 }
Makoto Onuki440a1ea2016-07-20 14:21:18 -07001497 final int last = mIntents.length - 1;
1498 final Intent intent = new Intent(mIntents[last]);
1499 return setIntentExtras(intent, mIntentPersistableExtrases[last]);
Makoto Onuki55046222016-03-08 10:49:47 -08001500 }
1501
1502 /**
Makoto Onuki347a6bd2016-07-19 11:13:08 -07001503 * Return the intent set with {@link Builder#setIntents(Intent[])}.
1504 *
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001505 * <p>Launcher apps <b>cannot</b> see the intents. If a {@link ShortcutInfo} is
Makoto Onuki347a6bd2016-07-19 11:13:08 -07001506 * obtained via {@link LauncherApps}, then this method will always return null.
1507 * Launchers can only start a shortcut intent with {@link LauncherApps#startShortcut}.
1508 *
1509 * @see Builder#setIntents(Intent[])
1510 */
1511 @Nullable
Makoto Onuki440a1ea2016-07-20 14:21:18 -07001512 public Intent[] getIntents() {
1513 final Intent[] ret = new Intent[mIntents.length];
1514
1515 for (int i = 0; i < ret.length; i++) {
1516 ret[i] = new Intent(mIntents[i]);
1517 setIntentExtras(ret[i], mIntentPersistableExtrases[i]);
1518 }
1519
1520 return ret;
Makoto Onuki347a6bd2016-07-19 11:13:08 -07001521 }
1522
1523 /**
Makoto Onuki440a1ea2016-07-20 14:21:18 -07001524 * Return "raw" intents, which is the original intents without the extras.
Makoto Onuki55046222016-03-08 10:49:47 -08001525 * @hide
1526 */
1527 @Nullable
Makoto Onuki440a1ea2016-07-20 14:21:18 -07001528 public Intent[] getIntentsNoExtras() {
1529 return mIntents;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001530 }
1531
Makoto Onuki55046222016-03-08 10:49:47 -08001532 /**
Mehdi Alizadeh14242af2018-12-20 20:11:35 -08001533 * Return the Persons set with {@link Builder#setPersons(Person[])}.
1534 *
1535 * @hide
1536 */
1537 @Nullable
Mehdi Alizadeh88873652019-02-04 14:16:46 -08001538 @SystemApi
Mehdi Alizadeh14242af2018-12-20 20:11:35 -08001539 public Person[] getPersons() {
1540 return clonePersons(mPersons);
1541 }
1542
1543 /**
Makoto Onuki440a1ea2016-07-20 14:21:18 -07001544 * The extras in the intents. We convert extras into {@link PersistableBundle} so we can
Makoto Onuki55046222016-03-08 10:49:47 -08001545 * persist them.
1546 * @hide
1547 */
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001548 @Nullable
Makoto Onuki440a1ea2016-07-20 14:21:18 -07001549 public PersistableBundle[] getIntentPersistableExtrases() {
1550 return mIntentPersistableExtrases;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001551 }
1552
Hakan Seyalioglu58fc95d2016-12-13 15:23:22 -08001553 /**
Makoto Onuki9e1f5592016-06-08 12:30:23 -07001554 * "Rank" of a shortcut, which is a non-negative, sequential value that's unique for each
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001555 * {@link #getActivity} for each of the two types of shortcuts (static and dynamic).
Makoto Onuki9e1f5592016-06-08 12:30:23 -07001556 *
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001557 * <p>Because static shortcuts and dynamic shortcuts have overlapping ranks,
1558 * when a launcher app shows shortcuts for an activity, it should first show
1559 * the static shortcuts, followed by the dynamic shortcuts. Within each of those categories,
Makoto Onuki9e1f5592016-06-08 12:30:23 -07001560 * shortcuts should be sorted by rank in ascending order.
1561 *
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001562 * <p><em>Floating shortcuts</em>, or shortcuts that are neither static nor dynamic, will all
1563 * have rank 0, because they aren't sorted.
Makoto Onuki4a910962016-07-07 13:57:34 -07001564 *
1565 * See the {@link ShortcutManager}'s class javadoc for details.
1566 *
1567 * @see Builder#setRank(int)
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001568 */
Makoto Onuki20c95f82016-05-11 16:51:01 -07001569 public int getRank() {
1570 return mRank;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001571 }
1572
Makoto Onuki9e1f5592016-06-08 12:30:23 -07001573 /** @hide */
1574 public boolean hasRank() {
1575 return mRank != RANK_NOT_SET;
1576 }
1577
1578 /** @hide */
1579 public void setRank(int rank) {
1580 mRank = rank;
1581 }
1582
1583 /** @hide */
1584 public void clearImplicitRankAndRankChangedFlag() {
1585 mImplicitRank = 0;
1586 }
1587
1588 /** @hide */
1589 public void setImplicitRank(int rank) {
1590 // Make sure to keep RANK_CHANGED_BIT.
1591 mImplicitRank = (mImplicitRank & RANK_CHANGED_BIT) | (rank & IMPLICIT_RANK_MASK);
1592 }
1593
1594 /** @hide */
1595 public int getImplicitRank() {
1596 return mImplicitRank & IMPLICIT_RANK_MASK;
1597 }
1598
1599 /** @hide */
1600 public void setRankChanged() {
1601 mImplicitRank |= RANK_CHANGED_BIT;
1602 }
1603
1604 /** @hide */
1605 public boolean isRankChanged() {
1606 return (mImplicitRank & RANK_CHANGED_BIT) != 0;
1607 }
1608
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001609 /**
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001610 * Extras that the app can set for any purpose.
Makoto Onuki4a910962016-07-07 13:57:34 -07001611 *
1612 * @see Builder#setExtras(PersistableBundle)
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001613 */
1614 @Nullable
1615 public PersistableBundle getExtras() {
1616 return mExtras;
1617 }
1618
Makoto Onukiabe84422016-04-07 09:41:19 -07001619 /** @hide */
1620 public int getUserId() {
1621 return mUserId;
1622 }
1623
1624 /**
Makoto Onukife9c9662016-07-25 15:12:23 -07001625 * {@link UserHandle} on which the publisher created this shortcut.
Makoto Onukiabe84422016-04-07 09:41:19 -07001626 */
1627 public UserHandle getUserHandle() {
1628 return UserHandle.of(mUserId);
1629 }
1630
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001631 /**
1632 * Last time when any of the fields was updated.
1633 */
1634 public long getLastChangedTimestamp() {
1635 return mLastChangedTimestamp;
1636 }
1637
1638 /** @hide */
1639 @ShortcutFlags
1640 public int getFlags() {
1641 return mFlags;
1642 }
1643
1644 /** @hide*/
Makoto Onukide667372016-03-15 14:29:20 -07001645 public void replaceFlags(@ShortcutFlags int flags) {
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001646 mFlags = flags;
1647 }
1648
1649 /** @hide*/
1650 public void addFlags(@ShortcutFlags int flags) {
1651 mFlags |= flags;
1652 }
1653
1654 /** @hide*/
1655 public void clearFlags(@ShortcutFlags int flags) {
1656 mFlags &= ~flags;
1657 }
1658
1659 /** @hide*/
1660 public boolean hasFlags(@ShortcutFlags int flags) {
1661 return (mFlags & flags) == flags;
1662 }
1663
Makoto Onukibf563b62017-05-04 10:25:30 -07001664 /** @hide */
1665 public boolean isReturnedByServer() {
1666 return hasFlags(FLAG_RETURNED_BY_SERVICE);
1667 }
1668
1669 /** @hide */
1670 public void setReturnedByServer() {
1671 addFlags(FLAG_RETURNED_BY_SERVICE);
1672 }
1673
Mehdi Alizadeh14242af2018-12-20 20:11:35 -08001674 /** @hide */
1675 public boolean isLongLived() {
1676 return hasFlags(FLAG_LONG_LIVED);
1677 }
1678
1679 /** @hide */
1680 public void setLongLived() {
1681 addFlags(FLAG_LONG_LIVED);
1682 }
1683
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001684 /** Return whether a shortcut is dynamic. */
1685 public boolean isDynamic() {
1686 return hasFlags(FLAG_DYNAMIC);
1687 }
1688
1689 /** Return whether a shortcut is pinned. */
1690 public boolean isPinned() {
1691 return hasFlags(FLAG_PINNED);
1692 }
1693
1694 /**
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001695 * Return whether a shortcut is static; that is, whether a shortcut is
1696 * published from AndroidManifest.xml. If {@code true}, the shortcut is
1697 * also {@link #isImmutable()}.
Makoto Onuki22fcc682016-05-17 14:52:19 -07001698 *
1699 * <p>When an app is upgraded and a shortcut is no longer published from AndroidManifest.xml,
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001700 * this will be set to {@code false}. If the shortcut is not pinned, then it'll disappear.
1701 * However, if it's pinned, it will still be visible, {@link #isEnabled()} will be
Makoto Onuki22fcc682016-05-17 14:52:19 -07001702 * {@code false} and {@link #isImmutable()} will be {@code true}.
Makoto Onuki20c95f82016-05-11 16:51:01 -07001703 */
Makoto Onukib5a012f2016-06-21 11:13:53 -07001704 public boolean isDeclaredInManifest() {
Makoto Onuki22fcc682016-05-17 14:52:19 -07001705 return hasFlags(FLAG_MANIFEST);
Makoto Onuki20c95f82016-05-11 16:51:01 -07001706 }
1707
Makoto Onukib5a012f2016-06-21 11:13:53 -07001708 /** @hide kept for unit tests */
1709 @Deprecated
1710 public boolean isManifestShortcut() {
1711 return isDeclaredInManifest();
1712 }
1713
Makoto Onuki22fcc682016-05-17 14:52:19 -07001714 /**
Makoto Onuki9fd90192017-01-06 18:31:03 +00001715 * @return true if pinned but neither static nor dynamic.
Makoto Onuki22fcc682016-05-17 14:52:19 -07001716 * @hide
1717 */
1718 public boolean isFloating() {
1719 return isPinned() && !(isDynamic() || isManifestShortcut());
1720 }
1721
1722 /** @hide */
1723 public boolean isOriginallyFromManifest() {
1724 return hasFlags(FLAG_IMMUTABLE);
1725 }
1726
Makoto Onukia4f89b12017-10-05 10:37:55 -07001727 /** @hide */
1728 public boolean isDynamicVisible() {
1729 return isDynamic() && isVisibleToPublisher();
1730 }
1731
1732 /** @hide */
1733 public boolean isPinnedVisible() {
1734 return isPinned() && isVisibleToPublisher();
1735 }
1736
1737 /** @hide */
1738 public boolean isManifestVisible() {
1739 return isDeclaredInManifest() && isVisibleToPublisher();
1740 }
1741
Makoto Onuki22fcc682016-05-17 14:52:19 -07001742 /**
1743 * Return if a shortcut is immutable, in which case it cannot be modified with any of
1744 * {@link ShortcutManager} APIs.
1745 *
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001746 * <p>All static shortcuts are immutable. When a static shortcut is pinned and is then
1747 * disabled because it doesn't appear in AndroidManifest.xml for a newer version of the
1748 * app, {@link #isDeclaredInManifest()} returns {@code false}, but the shortcut
1749 * is still immutable.
Makoto Onuki22fcc682016-05-17 14:52:19 -07001750 *
1751 * <p>All shortcuts originally published via the {@link ShortcutManager} APIs
1752 * are all mutable.
1753 */
1754 public boolean isImmutable() {
1755 return hasFlags(FLAG_IMMUTABLE);
1756 }
1757
1758 /**
1759 * Returns {@code false} if a shortcut is disabled with
1760 * {@link ShortcutManager#disableShortcuts}.
1761 */
1762 public boolean isEnabled() {
Makoto Onuki20c95f82016-05-11 16:51:01 -07001763 return !hasFlags(FLAG_DISABLED);
1764 }
1765
Makoto Onuki22fcc682016-05-17 14:52:19 -07001766 /** @hide */
1767 public boolean isAlive() {
1768 return hasFlags(FLAG_PINNED) || hasFlags(FLAG_DYNAMIC) || hasFlags(FLAG_MANIFEST);
1769 }
1770
1771 /** @hide */
1772 public boolean usesQuota() {
1773 return hasFlags(FLAG_DYNAMIC) || hasFlags(FLAG_MANIFEST);
1774 }
1775
Makoto Onuki20c95f82016-05-11 16:51:01 -07001776 /**
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001777 * Return whether a shortcut's icon is a resource in the owning package.
1778 *
Makoto Onukib5a012f2016-06-21 11:13:53 -07001779 * @hide internal/unit tests only
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001780 */
1781 public boolean hasIconResource() {
1782 return hasFlags(FLAG_HAS_ICON_RES);
1783 }
1784
Makoto Onuki20c95f82016-05-11 16:51:01 -07001785 /** @hide */
1786 public boolean hasStringResources() {
1787 return (mTitleResId != 0) || (mTextResId != 0) || (mDisabledMessageResId != 0);
1788 }
1789
1790 /** @hide */
1791 public boolean hasAnyResources() {
1792 return hasIconResource() || hasStringResources();
1793 }
1794
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001795 /**
1796 * Return whether a shortcut's icon is stored as a file.
1797 *
Makoto Onukib5a012f2016-06-21 11:13:53 -07001798 * @hide internal/unit tests only
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001799 */
1800 public boolean hasIconFile() {
1801 return hasFlags(FLAG_HAS_ICON_FILE);
1802 }
1803
Makoto Onuki55046222016-03-08 10:49:47 -08001804 /**
Hyunyoung Songe4179e22017-03-01 12:51:26 -08001805 * Return whether a shortcut's icon is adaptive bitmap following design guideline
Makoto Onukibf563b62017-05-04 10:25:30 -07001806 * defined in {@link android.graphics.drawable.AdaptiveIconDrawable}.
Hyunyoung Songf281e7a2017-02-13 10:57:42 -08001807 *
1808 * @hide internal/unit tests only
1809 */
Hyunyoung Songe4179e22017-03-01 12:51:26 -08001810 public boolean hasAdaptiveBitmap() {
1811 return hasFlags(FLAG_ADAPTIVE_BITMAP);
Hyunyoung Songf281e7a2017-02-13 10:57:42 -08001812 }
1813
Makoto Onuki475c3652017-05-08 14:29:03 -07001814 /** @hide */
1815 public boolean isIconPendingSave() {
1816 return hasFlags(FLAG_ICON_FILE_PENDING_SAVE);
1817 }
1818
1819 /** @hide */
1820 public void setIconPendingSave() {
1821 addFlags(FLAG_ICON_FILE_PENDING_SAVE);
1822 }
1823
1824 /** @hide */
1825 public void clearIconPendingSave() {
1826 clearFlags(FLAG_ICON_FILE_PENDING_SAVE);
1827 }
1828
Hyunyoung Songf281e7a2017-02-13 10:57:42 -08001829 /**
Makoto Onukia4f89b12017-10-05 10:37:55 -07001830 * When the system wasn't able to restore a shortcut, it'll still be registered to the system
1831 * but disabled, and such shortcuts will not be visible to the publisher. They're still visible
1832 * to launchers though.
1833 *
1834 * @hide
1835 */
1836 @TestApi
1837 public boolean isVisibleToPublisher() {
1838 return !isDisabledForRestoreIssue(mDisabledReason);
1839 }
1840
1841 /**
Makoto Onuki55046222016-03-08 10:49:47 -08001842 * Return whether a shortcut only contains "key" information only or not. If true, only the
1843 * following fields are available.
1844 * <ul>
1845 * <li>{@link #getId()}
Makoto Onuki22fcc682016-05-17 14:52:19 -07001846 * <li>{@link #getPackage()}
Makoto Onuki4d6b87f2016-06-17 13:47:40 -07001847 * <li>{@link #getActivity()}
Makoto Onuki55046222016-03-08 10:49:47 -08001848 * <li>{@link #getLastChangedTimestamp()}
1849 * <li>{@link #isDynamic()}
1850 * <li>{@link #isPinned()}
Makoto Onukib5a012f2016-06-21 11:13:53 -07001851 * <li>{@link #isDeclaredInManifest()}
1852 * <li>{@link #isImmutable()}
1853 * <li>{@link #isEnabled()}
1854 * <li>{@link #getUserHandle()}
Makoto Onuki55046222016-03-08 10:49:47 -08001855 * </ul>
Makoto Onuki4a910962016-07-07 13:57:34 -07001856 *
Makoto Onukife9c9662016-07-25 15:12:23 -07001857 * <p>For performance reasons, shortcuts passed to
1858 * {@link LauncherApps.Callback#onShortcutsChanged(String, List, UserHandle)} as well as those
1859 * returned from {@link LauncherApps#getShortcuts(ShortcutQuery, UserHandle)}
1860 * while using the {@link ShortcutQuery#FLAG_GET_KEY_FIELDS_ONLY} option contain only key
1861 * information.
Makoto Onuki55046222016-03-08 10:49:47 -08001862 */
1863 public boolean hasKeyFieldsOnly() {
1864 return hasFlags(FLAG_KEY_FIELDS_ONLY);
1865 }
1866
Makoto Onukib5a012f2016-06-21 11:13:53 -07001867 /** @hide */
Makoto Onuki20c95f82016-05-11 16:51:01 -07001868 public boolean hasStringResourcesResolved() {
1869 return hasFlags(FLAG_STRINGS_RESOLVED);
1870 }
1871
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001872 /** @hide */
1873 public void updateTimestamp() {
1874 mLastChangedTimestamp = System.currentTimeMillis();
1875 }
1876
1877 /** @hide */
1878 // VisibleForTesting
1879 public void setTimestamp(long value) {
1880 mLastChangedTimestamp = value;
1881 }
1882
1883 /** @hide */
Makoto Onuki55046222016-03-08 10:49:47 -08001884 public void clearIcon() {
1885 mIcon = null;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001886 }
1887
1888 /** @hide */
Makoto Onuki55046222016-03-08 10:49:47 -08001889 public void setIconResourceId(int iconResourceId) {
Makoto Onuki157b1622016-06-02 16:13:10 -07001890 if (mIconResId != iconResourceId) {
1891 mIconResName = null;
1892 }
1893 mIconResId = iconResourceId;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001894 }
1895
Makoto Onukib6d35232016-04-04 15:57:17 -07001896 /**
1897 * Get the resource ID for the icon, valid only when {@link #hasIconResource()} } is true.
Makoto Onukib5a012f2016-06-21 11:13:53 -07001898 * @hide internal / tests only.
Makoto Onukib6d35232016-04-04 15:57:17 -07001899 */
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001900 public int getIconResourceId() {
Makoto Onuki157b1622016-06-02 16:13:10 -07001901 return mIconResId;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001902 }
1903
Makoto Onuki475c3652017-05-08 14:29:03 -07001904 /**
1905 * Bitmap path. Note this will be null even if {@link #hasIconFile()} is set when the save
1906 * is pending. Use {@link #isIconPendingSave()} to check it.
1907 *
1908 * @hide
1909 */
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001910 public String getBitmapPath() {
1911 return mBitmapPath;
1912 }
1913
1914 /** @hide */
1915 public void setBitmapPath(String bitmapPath) {
1916 mBitmapPath = bitmapPath;
1917 }
1918
Makoto Onuki22fcc682016-05-17 14:52:19 -07001919 /** @hide */
1920 public void setDisabledMessageResId(int disabledMessageResId) {
Makoto Onuki157b1622016-06-02 16:13:10 -07001921 if (mDisabledMessageResId != disabledMessageResId) {
1922 mDisabledMessageResName = null;
1923 }
Makoto Onuki22fcc682016-05-17 14:52:19 -07001924 mDisabledMessageResId = disabledMessageResId;
1925 mDisabledMessage = null;
1926 }
1927
1928 /** @hide */
1929 public void setDisabledMessage(String disabledMessage) {
1930 mDisabledMessage = disabledMessage;
1931 mDisabledMessageResId = 0;
Makoto Onuki157b1622016-06-02 16:13:10 -07001932 mDisabledMessageResName = null;
1933 }
1934
1935 /** @hide */
1936 public String getTitleResName() {
1937 return mTitleResName;
1938 }
1939
1940 /** @hide */
1941 public void setTitleResName(String titleResName) {
1942 mTitleResName = titleResName;
1943 }
1944
1945 /** @hide */
1946 public String getTextResName() {
1947 return mTextResName;
1948 }
1949
1950 /** @hide */
1951 public void setTextResName(String textResName) {
1952 mTextResName = textResName;
1953 }
1954
1955 /** @hide */
1956 public String getDisabledMessageResName() {
1957 return mDisabledMessageResName;
1958 }
1959
1960 /** @hide */
1961 public void setDisabledMessageResName(String disabledMessageResName) {
1962 mDisabledMessageResName = disabledMessageResName;
1963 }
1964
1965 /** @hide */
1966 public String getIconResName() {
1967 return mIconResName;
1968 }
1969
1970 /** @hide */
1971 public void setIconResName(String iconResName) {
1972 mIconResName = iconResName;
Makoto Onuki22fcc682016-05-17 14:52:19 -07001973 }
1974
Makoto Onukidf6da042016-06-16 09:51:40 -07001975 /**
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001976 * Replaces the intent.
Makoto Onukidf6da042016-06-16 09:51:40 -07001977 *
1978 * @throws IllegalArgumentException when extra is not compatible with {@link PersistableBundle}.
1979 *
1980 * @hide
1981 */
Makoto Onuki440a1ea2016-07-20 14:21:18 -07001982 public void setIntents(Intent[] intents) throws IllegalArgumentException {
Daulet Zhanguzina2044e12019-12-30 16:34:59 +00001983 Objects.requireNonNull(intents);
Makoto Onuki440a1ea2016-07-20 14:21:18 -07001984 Preconditions.checkArgument(intents.length > 0);
Makoto Onukidf6da042016-06-16 09:51:40 -07001985
Makoto Onuki440a1ea2016-07-20 14:21:18 -07001986 mIntents = cloneIntents(intents);
1987 fixUpIntentExtras();
1988 }
Makoto Onukidf6da042016-06-16 09:51:40 -07001989
Makoto Onuki440a1ea2016-07-20 14:21:18 -07001990 /** @hide */
1991 public static Intent setIntentExtras(Intent intent, PersistableBundle extras) {
1992 if (extras == null) {
Makoto Onukidf6da042016-06-16 09:51:40 -07001993 intent.replaceExtras((Bundle) null);
Makoto Onukidf6da042016-06-16 09:51:40 -07001994 } else {
Makoto Onuki440a1ea2016-07-20 14:21:18 -07001995 intent.replaceExtras(new Bundle(extras));
Makoto Onukidf6da042016-06-16 09:51:40 -07001996 }
Makoto Onuki440a1ea2016-07-20 14:21:18 -07001997 return intent;
Makoto Onukidf6da042016-06-16 09:51:40 -07001998 }
1999
2000 /**
2001 * Replaces the categories.
2002 *
2003 * @hide
2004 */
2005 public void setCategories(Set<String> categories) {
2006 mCategories = cloneCategories(categories);
2007 }
2008
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002009 private ShortcutInfo(Parcel source) {
2010 final ClassLoader cl = getClass().getClassLoader();
2011
Makoto Onukiabe84422016-04-07 09:41:19 -07002012 mUserId = source.readInt();
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002013 mId = source.readString();
2014 mPackageName = source.readString();
Makoto Onuki22fcc682016-05-17 14:52:19 -07002015 mActivity = source.readParcelable(cl);
Makoto Onuki4d6b87f2016-06-17 13:47:40 -07002016 mFlags = source.readInt();
2017 mIconResId = source.readInt();
2018 mLastChangedTimestamp = source.readLong();
Makoto Onukia4f89b12017-10-05 10:37:55 -07002019 mDisabledReason = source.readInt();
Makoto Onuki4d6b87f2016-06-17 13:47:40 -07002020
2021 if (source.readInt() == 0) {
2022 return; // key information only.
2023 }
2024
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002025 mIcon = source.readParcelable(cl);
Makoto Onuki22fcc682016-05-17 14:52:19 -07002026 mTitle = source.readCharSequence();
Makoto Onuki20c95f82016-05-11 16:51:01 -07002027 mTitleResId = source.readInt();
Makoto Onuki22fcc682016-05-17 14:52:19 -07002028 mText = source.readCharSequence();
Makoto Onuki20c95f82016-05-11 16:51:01 -07002029 mTextResId = source.readInt();
Makoto Onuki22fcc682016-05-17 14:52:19 -07002030 mDisabledMessage = source.readCharSequence();
Makoto Onuki20c95f82016-05-11 16:51:01 -07002031 mDisabledMessageResId = source.readInt();
Makoto Onuki440a1ea2016-07-20 14:21:18 -07002032 mIntents = source.readParcelableArray(cl, Intent.class);
2033 mIntentPersistableExtrases = source.readParcelableArray(cl, PersistableBundle.class);
Makoto Onuki20c95f82016-05-11 16:51:01 -07002034 mRank = source.readInt();
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002035 mExtras = source.readParcelable(cl);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002036 mBitmapPath = source.readString();
Makoto Onukibe73a802016-04-15 14:46:35 -07002037
Makoto Onuki157b1622016-06-02 16:13:10 -07002038 mIconResName = source.readString();
2039 mTitleResName = source.readString();
2040 mTextResName = source.readString();
2041 mDisabledMessageResName = source.readString();
2042
Makoto Onukibe73a802016-04-15 14:46:35 -07002043 int N = source.readInt();
2044 if (N == 0) {
2045 mCategories = null;
2046 } else {
2047 mCategories = new ArraySet<>(N);
2048 for (int i = 0; i < N; i++) {
2049 mCategories.add(source.readString().intern());
2050 }
2051 }
Mehdi Alizadeh14242af2018-12-20 20:11:35 -08002052
2053 mPersons = source.readParcelableArray(cl, Person.class);
Felipe Leme90205ef2019-03-05 09:59:52 -08002054 mLocusId = source.readParcelable(cl);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002055 }
2056
2057 @Override
2058 public void writeToParcel(Parcel dest, int flags) {
Makoto Onukiabe84422016-04-07 09:41:19 -07002059 dest.writeInt(mUserId);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002060 dest.writeString(mId);
2061 dest.writeString(mPackageName);
Makoto Onuki22fcc682016-05-17 14:52:19 -07002062 dest.writeParcelable(mActivity, flags);
Makoto Onuki4d6b87f2016-06-17 13:47:40 -07002063 dest.writeInt(mFlags);
2064 dest.writeInt(mIconResId);
2065 dest.writeLong(mLastChangedTimestamp);
Makoto Onukia4f89b12017-10-05 10:37:55 -07002066 dest.writeInt(mDisabledReason);
Makoto Onuki4d6b87f2016-06-17 13:47:40 -07002067
2068 if (hasKeyFieldsOnly()) {
2069 dest.writeInt(0);
2070 return;
2071 }
2072 dest.writeInt(1);
2073
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002074 dest.writeParcelable(mIcon, flags);
Makoto Onuki22fcc682016-05-17 14:52:19 -07002075 dest.writeCharSequence(mTitle);
Makoto Onuki20c95f82016-05-11 16:51:01 -07002076 dest.writeInt(mTitleResId);
Makoto Onuki22fcc682016-05-17 14:52:19 -07002077 dest.writeCharSequence(mText);
Makoto Onuki20c95f82016-05-11 16:51:01 -07002078 dest.writeInt(mTextResId);
Makoto Onuki22fcc682016-05-17 14:52:19 -07002079 dest.writeCharSequence(mDisabledMessage);
Makoto Onuki20c95f82016-05-11 16:51:01 -07002080 dest.writeInt(mDisabledMessageResId);
Makoto Onukibe73a802016-04-15 14:46:35 -07002081
Makoto Onuki440a1ea2016-07-20 14:21:18 -07002082 dest.writeParcelableArray(mIntents, flags);
2083 dest.writeParcelableArray(mIntentPersistableExtrases, flags);
Makoto Onuki20c95f82016-05-11 16:51:01 -07002084 dest.writeInt(mRank);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002085 dest.writeParcelable(mExtras, flags);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002086 dest.writeString(mBitmapPath);
Makoto Onukibe73a802016-04-15 14:46:35 -07002087
Makoto Onuki157b1622016-06-02 16:13:10 -07002088 dest.writeString(mIconResName);
2089 dest.writeString(mTitleResName);
2090 dest.writeString(mTextResName);
2091 dest.writeString(mDisabledMessageResName);
2092
Makoto Onukibe73a802016-04-15 14:46:35 -07002093 if (mCategories != null) {
2094 final int N = mCategories.size();
2095 dest.writeInt(N);
2096 for (int i = 0; i < N; i++) {
2097 dest.writeString(mCategories.valueAt(i));
2098 }
2099 } else {
2100 dest.writeInt(0);
2101 }
Mehdi Alizadeh14242af2018-12-20 20:11:35 -08002102
2103 dest.writeParcelableArray(mPersons, flags);
Felipe Leme90205ef2019-03-05 09:59:52 -08002104 dest.writeParcelable(mLocusId, flags);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002105 }
2106
Jeff Sharkey9e8f83d2019-02-28 12:06:45 -07002107 public static final @android.annotation.NonNull Creator<ShortcutInfo> CREATOR =
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002108 new Creator<ShortcutInfo>() {
2109 public ShortcutInfo createFromParcel(Parcel source) {
2110 return new ShortcutInfo(source);
2111 }
2112 public ShortcutInfo[] newArray(int size) {
2113 return new ShortcutInfo[size];
2114 }
2115 };
2116
2117 @Override
2118 public int describeContents() {
2119 return 0;
2120 }
2121
Makoto Onuki6208c672017-10-02 16:20:35 -07002122
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002123 /**
2124 * Return a string representation, intended for logging. Some fields will be retracted.
2125 */
2126 @Override
2127 public String toString() {
Makoto Onuki6208c672017-10-02 16:20:35 -07002128 return toStringInner(/* secure =*/ true, /* includeInternalData =*/ false,
2129 /*indent=*/ null);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002130 }
2131
2132 /** @hide */
2133 public String toInsecureString() {
Makoto Onuki6208c672017-10-02 16:20:35 -07002134 return toStringInner(/* secure =*/ false, /* includeInternalData =*/ true,
2135 /*indent=*/ null);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002136 }
2137
Makoto Onuki6208c672017-10-02 16:20:35 -07002138 /** @hide */
2139 public String toDumpString(String indent) {
2140 return toStringInner(/* secure =*/ false, /* includeInternalData =*/ true, indent);
2141 }
2142
2143 private void addIndentOrComma(StringBuilder sb, String indent) {
2144 if (indent != null) {
2145 sb.append("\n ");
2146 sb.append(indent);
2147 } else {
2148 sb.append(", ");
2149 }
2150 }
2151
2152 private String toStringInner(boolean secure, boolean includeInternalData, String indent) {
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002153 final StringBuilder sb = new StringBuilder();
Makoto Onuki6208c672017-10-02 16:20:35 -07002154
2155 if (indent != null) {
2156 sb.append(indent);
2157 }
2158
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002159 sb.append("ShortcutInfo {");
2160
2161 sb.append("id=");
2162 sb.append(secure ? "***" : mId);
2163
Makoto Onuki22fcc682016-05-17 14:52:19 -07002164 sb.append(", flags=0x");
2165 sb.append(Integer.toHexString(mFlags));
2166 sb.append(" [");
Makoto Onukia4f89b12017-10-05 10:37:55 -07002167 if ((mFlags & FLAG_SHADOW) != 0) {
2168 // Note the shadow flag isn't actually used anywhere and it's just for dumpsys, so
2169 // we don't have an isXxx for this.
2170 sb.append("Sdw");
2171 }
Makoto Onuki22fcc682016-05-17 14:52:19 -07002172 if (!isEnabled()) {
Makoto Onuki6208c672017-10-02 16:20:35 -07002173 sb.append("Dis");
Makoto Onuki22fcc682016-05-17 14:52:19 -07002174 }
2175 if (isImmutable()) {
2176 sb.append("Im");
2177 }
2178 if (isManifestShortcut()) {
Makoto Onuki6208c672017-10-02 16:20:35 -07002179 sb.append("Man");
Makoto Onuki22fcc682016-05-17 14:52:19 -07002180 }
2181 if (isDynamic()) {
Makoto Onuki6208c672017-10-02 16:20:35 -07002182 sb.append("Dyn");
Makoto Onuki22fcc682016-05-17 14:52:19 -07002183 }
2184 if (isPinned()) {
Makoto Onuki6208c672017-10-02 16:20:35 -07002185 sb.append("Pin");
Makoto Onuki22fcc682016-05-17 14:52:19 -07002186 }
2187 if (hasIconFile()) {
Makoto Onuki6208c672017-10-02 16:20:35 -07002188 sb.append("Ic-f");
Makoto Onuki22fcc682016-05-17 14:52:19 -07002189 }
Makoto Onuki475c3652017-05-08 14:29:03 -07002190 if (isIconPendingSave()) {
Makoto Onuki6208c672017-10-02 16:20:35 -07002191 sb.append("Pens");
Makoto Onuki475c3652017-05-08 14:29:03 -07002192 }
Makoto Onuki22fcc682016-05-17 14:52:19 -07002193 if (hasIconResource()) {
Makoto Onuki6208c672017-10-02 16:20:35 -07002194 sb.append("Ic-r");
Makoto Onuki22fcc682016-05-17 14:52:19 -07002195 }
2196 if (hasKeyFieldsOnly()) {
Makoto Onuki6208c672017-10-02 16:20:35 -07002197 sb.append("Key");
Makoto Onuki22fcc682016-05-17 14:52:19 -07002198 }
2199 if (hasStringResourcesResolved()) {
Makoto Onuki6208c672017-10-02 16:20:35 -07002200 sb.append("Str");
Makoto Onuki22fcc682016-05-17 14:52:19 -07002201 }
Makoto Onukibf563b62017-05-04 10:25:30 -07002202 if (isReturnedByServer()) {
Makoto Onuki6208c672017-10-02 16:20:35 -07002203 sb.append("Rets");
Makoto Onukibf563b62017-05-04 10:25:30 -07002204 }
Mehdi Alizadeh14242af2018-12-20 20:11:35 -08002205 if (isLongLived()) {
2206 sb.append("Liv");
2207 }
Makoto Onuki22fcc682016-05-17 14:52:19 -07002208 sb.append("]");
2209
Makoto Onuki6208c672017-10-02 16:20:35 -07002210 addIndentOrComma(sb, indent);
2211
2212 sb.append("packageName=");
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002213 sb.append(mPackageName);
2214
Makoto Onukia4f89b12017-10-05 10:37:55 -07002215 addIndentOrComma(sb, indent);
2216
2217 sb.append("activity=");
Makoto Onuki22fcc682016-05-17 14:52:19 -07002218 sb.append(mActivity);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002219
Makoto Onuki6208c672017-10-02 16:20:35 -07002220 addIndentOrComma(sb, indent);
2221
2222 sb.append("shortLabel=");
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002223 sb.append(secure ? "***" : mTitle);
Makoto Onukieddbfec2016-05-31 17:04:34 -07002224 sb.append(", resId=");
Makoto Onuki20c95f82016-05-11 16:51:01 -07002225 sb.append(mTitleResId);
Makoto Onuki157b1622016-06-02 16:13:10 -07002226 sb.append("[");
2227 sb.append(mTitleResName);
2228 sb.append("]");
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002229
Makoto Onuki6208c672017-10-02 16:20:35 -07002230 addIndentOrComma(sb, indent);
2231
2232 sb.append("longLabel=");
Makoto Onukie3ae7ec2016-03-29 15:45:25 -07002233 sb.append(secure ? "***" : mText);
Makoto Onukieddbfec2016-05-31 17:04:34 -07002234 sb.append(", resId=");
Makoto Onuki20c95f82016-05-11 16:51:01 -07002235 sb.append(mTextResId);
Makoto Onuki157b1622016-06-02 16:13:10 -07002236 sb.append("[");
2237 sb.append(mTextResName);
2238 sb.append("]");
Makoto Onuki20c95f82016-05-11 16:51:01 -07002239
Makoto Onuki6208c672017-10-02 16:20:35 -07002240 addIndentOrComma(sb, indent);
2241
2242 sb.append("disabledMessage=");
Makoto Onuki20c95f82016-05-11 16:51:01 -07002243 sb.append(secure ? "***" : mDisabledMessage);
Makoto Onukieddbfec2016-05-31 17:04:34 -07002244 sb.append(", resId=");
Makoto Onuki20c95f82016-05-11 16:51:01 -07002245 sb.append(mDisabledMessageResId);
Makoto Onuki157b1622016-06-02 16:13:10 -07002246 sb.append("[");
2247 sb.append(mDisabledMessageResName);
2248 sb.append("]");
Makoto Onukie3ae7ec2016-03-29 15:45:25 -07002249
Makoto Onuki6208c672017-10-02 16:20:35 -07002250 addIndentOrComma(sb, indent);
2251
Makoto Onukia4f89b12017-10-05 10:37:55 -07002252 sb.append("disabledReason=");
Makoto Onukib1588c02017-10-12 15:11:45 -07002253 sb.append(getDisabledReasonDebugString(mDisabledReason));
Makoto Onukia4f89b12017-10-05 10:37:55 -07002254
2255 addIndentOrComma(sb, indent);
2256
Makoto Onuki6208c672017-10-02 16:20:35 -07002257 sb.append("categories=");
Makoto Onukib6d35232016-04-04 15:57:17 -07002258 sb.append(mCategories);
2259
Makoto Onuki6208c672017-10-02 16:20:35 -07002260 addIndentOrComma(sb, indent);
2261
Mehdi Alizadeh14242af2018-12-20 20:11:35 -08002262 sb.append("persons=");
2263 sb.append(mPersons);
2264
2265 addIndentOrComma(sb, indent);
2266
Makoto Onuki6208c672017-10-02 16:20:35 -07002267 sb.append("icon=");
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002268 sb.append(mIcon);
2269
Makoto Onuki6208c672017-10-02 16:20:35 -07002270 addIndentOrComma(sb, indent);
2271
2272 sb.append("rank=");
Makoto Onuki20c95f82016-05-11 16:51:01 -07002273 sb.append(mRank);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002274
2275 sb.append(", timestamp=");
2276 sb.append(mLastChangedTimestamp);
2277
Makoto Onuki6208c672017-10-02 16:20:35 -07002278 addIndentOrComma(sb, indent);
2279
2280 sb.append("intents=");
Makoto Onuki440a1ea2016-07-20 14:21:18 -07002281 if (mIntents == null) {
2282 sb.append("null");
2283 } else {
2284 if (secure) {
2285 sb.append("size:");
2286 sb.append(mIntents.length);
2287 } else {
2288 final int size = mIntents.length;
2289 sb.append("[");
2290 String sep = "";
2291 for (int i = 0; i < size; i++) {
2292 sb.append(sep);
2293 sep = ", ";
2294 sb.append(mIntents[i]);
2295 sb.append("/");
2296 sb.append(mIntentPersistableExtrases[i]);
2297 }
2298 sb.append("]");
2299 }
2300 }
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002301
Makoto Onuki6208c672017-10-02 16:20:35 -07002302 addIndentOrComma(sb, indent);
2303
2304 sb.append("extras=");
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002305 sb.append(mExtras);
2306
2307 if (includeInternalData) {
Makoto Onuki6208c672017-10-02 16:20:35 -07002308 addIndentOrComma(sb, indent);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002309
Makoto Onuki6208c672017-10-02 16:20:35 -07002310 sb.append("iconRes=");
Makoto Onuki157b1622016-06-02 16:13:10 -07002311 sb.append(mIconResId);
2312 sb.append("[");
2313 sb.append(mIconResName);
2314 sb.append("]");
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002315
2316 sb.append(", bitmapPath=");
2317 sb.append(mBitmapPath);
2318 }
2319
Felipe Leme90205ef2019-03-05 09:59:52 -08002320 if (mLocusId != null) {
2321 sb.append("locusId="); sb.append(mLocusId); // LocusId.toString() is PII-safe.
2322 }
2323
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002324 sb.append("}");
2325 return sb.toString();
2326 }
2327
2328 /** @hide */
Makoto Onukiabe84422016-04-07 09:41:19 -07002329 public ShortcutInfo(
Makoto Onuki22fcc682016-05-17 14:52:19 -07002330 @UserIdInt int userId, String id, String packageName, ComponentName activity,
Makoto Onuki157b1622016-06-02 16:13:10 -07002331 Icon icon, CharSequence title, int titleResId, String titleResName,
2332 CharSequence text, int textResId, String textResName,
2333 CharSequence disabledMessage, int disabledMessageResId, String disabledMessageResName,
Makoto Onuki440a1ea2016-07-20 14:21:18 -07002334 Set<String> categories, Intent[] intentsWithExtras, int rank, PersistableBundle extras,
2335 long lastChangedTimestamp,
Mehdi Alizadehebb4b602019-02-05 15:52:18 -08002336 int flags, int iconResId, String iconResName, String bitmapPath, int disabledReason,
Felipe Leme90205ef2019-03-05 09:59:52 -08002337 Person[] persons, LocusId locusId) {
Makoto Onukiabe84422016-04-07 09:41:19 -07002338 mUserId = userId;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002339 mId = id;
2340 mPackageName = packageName;
Makoto Onuki22fcc682016-05-17 14:52:19 -07002341 mActivity = activity;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002342 mIcon = icon;
2343 mTitle = title;
Makoto Onuki20c95f82016-05-11 16:51:01 -07002344 mTitleResId = titleResId;
Makoto Onuki157b1622016-06-02 16:13:10 -07002345 mTitleResName = titleResName;
Makoto Onukie3ae7ec2016-03-29 15:45:25 -07002346 mText = text;
Makoto Onuki20c95f82016-05-11 16:51:01 -07002347 mTextResId = textResId;
Makoto Onuki157b1622016-06-02 16:13:10 -07002348 mTextResName = textResName;
Makoto Onuki20c95f82016-05-11 16:51:01 -07002349 mDisabledMessage = disabledMessage;
2350 mDisabledMessageResId = disabledMessageResId;
Makoto Onuki157b1622016-06-02 16:13:10 -07002351 mDisabledMessageResName = disabledMessageResName;
Makoto Onukidf6da042016-06-16 09:51:40 -07002352 mCategories = cloneCategories(categories);
Makoto Onuki440a1ea2016-07-20 14:21:18 -07002353 mIntents = cloneIntents(intentsWithExtras);
2354 fixUpIntentExtras();
Makoto Onuki20c95f82016-05-11 16:51:01 -07002355 mRank = rank;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002356 mExtras = extras;
2357 mLastChangedTimestamp = lastChangedTimestamp;
2358 mFlags = flags;
Makoto Onuki157b1622016-06-02 16:13:10 -07002359 mIconResId = iconResId;
2360 mIconResName = iconResName;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002361 mBitmapPath = bitmapPath;
Makoto Onukia4f89b12017-10-05 10:37:55 -07002362 mDisabledReason = disabledReason;
Mehdi Alizadehebb4b602019-02-05 15:52:18 -08002363 mPersons = persons;
Felipe Leme90205ef2019-03-05 09:59:52 -08002364 mLocusId = locusId;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002365 }
2366}