blob: 7b61807f9684dbc5fcc5b7e0c1870f001e55ead8 [file] [log] [blame]
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package android.content.pm;
17
18import android.annotation.IntDef;
19import android.annotation.NonNull;
20import android.annotation.Nullable;
Mehdi Alizadeh88873652019-02-04 14:16:46 -080021import android.annotation.SystemApi;
Makoto Onukia4f89b12017-10-05 10:37:55 -070022import android.annotation.TestApi;
Mathew Inwood5c0d3542018-08-14 13:54:31 +010023import android.annotation.UnsupportedAppUsage;
Makoto Onukiabe84422016-04-07 09:41:19 -070024import android.annotation.UserIdInt;
Felipe Leme90205ef2019-03-05 09:59:52 -080025import android.app.Notification;
Mehdi Alizadeh14242af2018-12-20 20:11:35 -080026import android.app.Person;
Makoto Onuki347a6bd2016-07-19 11:13:08 -070027import android.app.TaskStackBuilder;
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;
Makoto Onukibe73a802016-04-15 14:46:35 -070054import java.util.Set;
Makoto Onuki6f7362d92016-03-04 13:39:41 -080055
56/**
Kevin Hufnagle68d699d2016-10-14 19:04:51 -070057 * Represents a shortcut that can be published via {@link ShortcutManager}.
Makoto Onuki6f7362d92016-03-04 13:39:41 -080058 *
Makoto Onuki4a910962016-07-07 13:57:34 -070059 * @see ShortcutManager
Makoto Onuki6f7362d92016-03-04 13:39:41 -080060 */
Jeff Sharkey70168dd2016-03-30 21:47:16 -060061public final class ShortcutInfo implements Parcelable {
Makoto Onuki157b1622016-06-02 16:13:10 -070062 static final String TAG = "Shortcut";
63
64 private static final String RES_TYPE_STRING = "string";
65
66 private static final String ANDROID_PACKAGE_NAME = "android";
67
Makoto Onuki9e1f5592016-06-08 12:30:23 -070068 private static final int IMPLICIT_RANK_MASK = 0x7fffffff;
69
70 private static final int RANK_CHANGED_BIT = ~IMPLICIT_RANK_MASK;
71
72 /** @hide */
73 public static final int RANK_NOT_SET = Integer.MAX_VALUE;
74
Makoto Onuki157b1622016-06-02 16:13:10 -070075 /** @hide */
Makoto Onuki6f7362d92016-03-04 13:39:41 -080076 public static final int FLAG_DYNAMIC = 1 << 0;
77
Makoto Onuki157b1622016-06-02 16:13:10 -070078 /** @hide */
Makoto Onuki6f7362d92016-03-04 13:39:41 -080079 public static final int FLAG_PINNED = 1 << 1;
80
Makoto Onuki157b1622016-06-02 16:13:10 -070081 /** @hide */
Makoto Onuki6f7362d92016-03-04 13:39:41 -080082 public static final int FLAG_HAS_ICON_RES = 1 << 2;
83
Makoto Onuki157b1622016-06-02 16:13:10 -070084 /** @hide */
Makoto Onuki6f7362d92016-03-04 13:39:41 -080085 public static final int FLAG_HAS_ICON_FILE = 1 << 3;
86
Makoto Onuki157b1622016-06-02 16:13:10 -070087 /** @hide */
Makoto Onuki55046222016-03-08 10:49:47 -080088 public static final int FLAG_KEY_FIELDS_ONLY = 1 << 4;
89
Makoto Onuki157b1622016-06-02 16:13:10 -070090 /** @hide */
Makoto Onuki22fcc682016-05-17 14:52:19 -070091 public static final int FLAG_MANIFEST = 1 << 5;
Makoto Onuki20c95f82016-05-11 16:51:01 -070092
Makoto Onuki157b1622016-06-02 16:13:10 -070093 /** @hide */
Makoto Onuki20c95f82016-05-11 16:51:01 -070094 public static final int FLAG_DISABLED = 1 << 6;
95
Makoto Onuki157b1622016-06-02 16:13:10 -070096 /** @hide */
Makoto Onuki20c95f82016-05-11 16:51:01 -070097 public static final int FLAG_STRINGS_RESOLVED = 1 << 7;
98
Makoto Onuki157b1622016-06-02 16:13:10 -070099 /** @hide */
Makoto Onuki22fcc682016-05-17 14:52:19 -0700100 public static final int FLAG_IMMUTABLE = 1 << 8;
101
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800102 /** @hide */
Hyunyoung Songe4179e22017-03-01 12:51:26 -0800103 public static final int FLAG_ADAPTIVE_BITMAP = 1 << 9;
Hyunyoung Songf281e7a2017-02-13 10:57:42 -0800104
105 /** @hide */
Makoto Onukibf563b62017-05-04 10:25:30 -0700106 public static final int FLAG_RETURNED_BY_SERVICE = 1 << 10;
107
Makoto Onuki475c3652017-05-08 14:29:03 -0700108 /** @hide When this is set, the bitmap icon is waiting to be saved. */
109 public static final int FLAG_ICON_FILE_PENDING_SAVE = 1 << 11;
110
Makoto Onukia4f89b12017-10-05 10:37:55 -0700111 /**
112 * "Shadow" shortcuts are the ones that are restored, but the owner package hasn't been
113 * installed yet.
114 * @hide
115 */
116 public static final int FLAG_SHADOW = 1 << 12;
117
Makoto Onukibf563b62017-05-04 10:25:30 -0700118 /** @hide */
Mehdi Alizadeh14242af2018-12-20 20:11:35 -0800119 public static final int FLAG_LONG_LIVED = 1 << 13;
120
121 /** @hide */
Jeff Sharkeyce8db992017-12-13 20:05:05 -0700122 @IntDef(flag = true, prefix = { "FLAG_" }, value = {
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800123 FLAG_DYNAMIC,
124 FLAG_PINNED,
125 FLAG_HAS_ICON_RES,
126 FLAG_HAS_ICON_FILE,
Makoto Onuki55046222016-03-08 10:49:47 -0800127 FLAG_KEY_FIELDS_ONLY,
Makoto Onuki22fcc682016-05-17 14:52:19 -0700128 FLAG_MANIFEST,
Makoto Onuki20c95f82016-05-11 16:51:01 -0700129 FLAG_DISABLED,
130 FLAG_STRINGS_RESOLVED,
Makoto Onuki22fcc682016-05-17 14:52:19 -0700131 FLAG_IMMUTABLE,
Hyunyoung Songe4179e22017-03-01 12:51:26 -0800132 FLAG_ADAPTIVE_BITMAP,
Makoto Onuki475c3652017-05-08 14:29:03 -0700133 FLAG_RETURNED_BY_SERVICE,
134 FLAG_ICON_FILE_PENDING_SAVE,
Mehdi Alizadeh14242af2018-12-20 20:11:35 -0800135 FLAG_SHADOW,
136 FLAG_LONG_LIVED,
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800137 })
138 @Retention(RetentionPolicy.SOURCE)
139 public @interface ShortcutFlags {}
140
141 // Cloning options.
142
Makoto Onuki157b1622016-06-02 16:13:10 -0700143 /** @hide */
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800144 private static final int CLONE_REMOVE_ICON = 1 << 0;
145
Makoto Onuki157b1622016-06-02 16:13:10 -0700146 /** @hide */
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800147 private static final int CLONE_REMOVE_INTENT = 1 << 1;
148
Makoto Onuki157b1622016-06-02 16:13:10 -0700149 /** @hide */
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800150 public static final int CLONE_REMOVE_NON_KEY_INFO = 1 << 2;
151
Makoto Onuki157b1622016-06-02 16:13:10 -0700152 /** @hide */
153 public static final int CLONE_REMOVE_RES_NAMES = 1 << 3;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800154
Makoto Onuki157b1622016-06-02 16:13:10 -0700155 /** @hide */
156 public static final int CLONE_REMOVE_FOR_CREATOR = CLONE_REMOVE_ICON | CLONE_REMOVE_RES_NAMES;
157
158 /** @hide */
159 public static final int CLONE_REMOVE_FOR_LAUNCHER = CLONE_REMOVE_ICON | CLONE_REMOVE_INTENT
160 | CLONE_REMOVE_RES_NAMES;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800161
162 /** @hide */
Makoto Onukia01f4f02016-12-15 15:58:41 -0800163 public static final int CLONE_REMOVE_FOR_LAUNCHER_APPROVAL = CLONE_REMOVE_INTENT
164 | CLONE_REMOVE_RES_NAMES;
165
166 /** @hide */
Jeff Sharkeyce8db992017-12-13 20:05:05 -0700167 @IntDef(flag = true, prefix = { "CLONE_" }, value = {
168 CLONE_REMOVE_ICON,
169 CLONE_REMOVE_INTENT,
170 CLONE_REMOVE_NON_KEY_INFO,
171 CLONE_REMOVE_RES_NAMES,
172 CLONE_REMOVE_FOR_CREATOR,
173 CLONE_REMOVE_FOR_LAUNCHER
174 })
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800175 @Retention(RetentionPolicy.SOURCE)
176 public @interface CloneFlags {}
177
Makoto Onukib6d35232016-04-04 15:57:17 -0700178 /**
Makoto Onukia4f89b12017-10-05 10:37:55 -0700179 * Shortcut is not disabled.
180 */
181 public static final int DISABLED_REASON_NOT_DISABLED = 0;
182
183 /**
184 * Shortcut has been disabled by the publisher app with the
185 * {@link ShortcutManager#disableShortcuts(List)} API.
186 */
187 public static final int DISABLED_REASON_BY_APP = 1;
188
189 /**
190 * Shortcut has been disabled due to changes to the publisher app. (e.g. a manifest shortcut
191 * no longer exists.)
192 */
193 public static final int DISABLED_REASON_APP_CHANGED = 2;
194
195 /**
Makoto Onuki5482a8e62018-01-09 10:31:08 -0800196 * Shortcut is disabled for an unknown reason.
197 */
198 public static final int DISABLED_REASON_UNKNOWN = 3;
199
200 /**
Makoto Onukia4f89b12017-10-05 10:37:55 -0700201 * A disabled reason that's equal to or bigger than this is due to backup and restore issue.
202 * A shortcut with such a reason wil be visible to the launcher, but not to the publisher.
203 * ({@link #isVisibleToPublisher()} will be false.)
204 */
205 private static final int DISABLED_REASON_RESTORE_ISSUE_START = 100;
206
207 /**
208 * Shortcut has been restored from the previous device, but the publisher app on the current
209 * device is of a lower version. The shortcut will not be usable until the app is upgraded to
210 * the same version or higher.
211 */
212 public static final int DISABLED_REASON_VERSION_LOWER = 100;
213
214 /**
215 * Shortcut has not been restored because the publisher app does not support backup and restore.
216 */
217 public static final int DISABLED_REASON_BACKUP_NOT_SUPPORTED = 101;
218
219 /**
220 * Shortcut has not been restored because the publisher app's signature has changed.
221 */
222 public static final int DISABLED_REASON_SIGNATURE_MISMATCH = 102;
223
224 /**
225 * Shortcut has not been restored for unknown reason.
226 */
227 public static final int DISABLED_REASON_OTHER_RESTORE_ISSUE = 103;
228
229 /** @hide */
Jeff Sharkeyce8db992017-12-13 20:05:05 -0700230 @IntDef(prefix = { "DISABLED_REASON_" }, value = {
Makoto Onukia4f89b12017-10-05 10:37:55 -0700231 DISABLED_REASON_NOT_DISABLED,
232 DISABLED_REASON_BY_APP,
233 DISABLED_REASON_APP_CHANGED,
Makoto Onuki5482a8e62018-01-09 10:31:08 -0800234 DISABLED_REASON_UNKNOWN,
Makoto Onukia4f89b12017-10-05 10:37:55 -0700235 DISABLED_REASON_VERSION_LOWER,
236 DISABLED_REASON_BACKUP_NOT_SUPPORTED,
237 DISABLED_REASON_SIGNATURE_MISMATCH,
238 DISABLED_REASON_OTHER_RESTORE_ISSUE,
Jeff Sharkeyce8db992017-12-13 20:05:05 -0700239 })
Makoto Onukia4f89b12017-10-05 10:37:55 -0700240 @Retention(RetentionPolicy.SOURCE)
241 public @interface DisabledReason{}
242
Makoto Onukib1588c02017-10-12 15:11:45 -0700243 /**
244 * Return a label for disabled reasons, which are *not* supposed to be shown to the user.
245 * @hide
246 */
247 public static String getDisabledReasonDebugString(@DisabledReason int disabledReason) {
Makoto Onukia4f89b12017-10-05 10:37:55 -0700248 switch (disabledReason) {
249 case DISABLED_REASON_NOT_DISABLED:
250 return "[Not disabled]";
251 case DISABLED_REASON_BY_APP:
252 return "[Disabled: by app]";
253 case DISABLED_REASON_APP_CHANGED:
254 return "[Disabled: app changed]";
255 case DISABLED_REASON_VERSION_LOWER:
256 return "[Disabled: lower version]";
257 case DISABLED_REASON_BACKUP_NOT_SUPPORTED:
258 return "[Disabled: backup not supported]";
259 case DISABLED_REASON_SIGNATURE_MISMATCH:
260 return "[Disabled: signature mismatch]";
261 case DISABLED_REASON_OTHER_RESTORE_ISSUE:
262 return "[Disabled: unknown restore issue]";
263 }
264 return "[Disabled: unknown reason:" + disabledReason + "]";
265 }
266
Makoto Onukib1588c02017-10-12 15:11:45 -0700267 /**
268 * Return a label for a disabled reason for shortcuts that are disabled due to a backup and
269 * restore issue. If the reason is not due to backup & restore, then it'll return null.
270 *
271 * This method returns localized, user-facing strings, which will be returned by
272 * {@link #getDisabledMessage()}.
273 *
274 * @hide
275 */
276 public static String getDisabledReasonForRestoreIssue(Context context,
277 @DisabledReason int disabledReason) {
278 final Resources res = context.getResources();
279
280 switch (disabledReason) {
281 case DISABLED_REASON_VERSION_LOWER:
282 return res.getString(
283 com.android.internal.R.string.shortcut_restored_on_lower_version);
284 case DISABLED_REASON_BACKUP_NOT_SUPPORTED:
285 return res.getString(
286 com.android.internal.R.string.shortcut_restore_not_supported);
287 case DISABLED_REASON_SIGNATURE_MISMATCH:
288 return res.getString(
289 com.android.internal.R.string.shortcut_restore_signature_mismatch);
290 case DISABLED_REASON_OTHER_RESTORE_ISSUE:
291 return res.getString(
292 com.android.internal.R.string.shortcut_restore_unknown_issue);
Makoto Onuki5482a8e62018-01-09 10:31:08 -0800293 case DISABLED_REASON_UNKNOWN:
294 return res.getString(
295 com.android.internal.R.string.shortcut_disabled_reason_unknown);
Makoto Onukib1588c02017-10-12 15:11:45 -0700296 }
297 return null;
298 }
299
Makoto Onukia4f89b12017-10-05 10:37:55 -0700300 /** @hide */
301 public static boolean isDisabledForRestoreIssue(@DisabledReason int disabledReason) {
302 return disabledReason >= DISABLED_REASON_RESTORE_ISSUE_START;
303 }
304
305 /**
Makoto Onuki4a910962016-07-07 13:57:34 -0700306 * Shortcut category for messaging related actions, such as chat.
Makoto Onukib6d35232016-04-04 15:57:17 -0700307 */
308 public static final String SHORTCUT_CATEGORY_CONVERSATION = "android.shortcut.conversation";
309
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800310 private final String mId;
311
312 @NonNull
313 private final String mPackageName;
314
315 @Nullable
Makoto Onuki22fcc682016-05-17 14:52:19 -0700316 private ComponentName mActivity;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800317
318 @Nullable
319 private Icon mIcon;
320
Makoto Onuki20c95f82016-05-11 16:51:01 -0700321 private int mTitleResId;
322
Makoto Onuki157b1622016-06-02 16:13:10 -0700323 private String mTitleResName;
324
Makoto Onuki20c95f82016-05-11 16:51:01 -0700325 @Nullable
Makoto Onuki22fcc682016-05-17 14:52:19 -0700326 private CharSequence mTitle;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800327
Makoto Onuki20c95f82016-05-11 16:51:01 -0700328 private int mTextResId;
329
Makoto Onuki157b1622016-06-02 16:13:10 -0700330 private String mTextResName;
331
Makoto Onukie3ae7ec2016-03-29 15:45:25 -0700332 @Nullable
Makoto Onuki22fcc682016-05-17 14:52:19 -0700333 private CharSequence mText;
Makoto Onukie3ae7ec2016-03-29 15:45:25 -0700334
Makoto Onuki20c95f82016-05-11 16:51:01 -0700335 private int mDisabledMessageResId;
336
Makoto Onuki157b1622016-06-02 16:13:10 -0700337 private String mDisabledMessageResName;
338
Makoto Onuki20c95f82016-05-11 16:51:01 -0700339 @Nullable
Makoto Onuki22fcc682016-05-17 14:52:19 -0700340 private CharSequence mDisabledMessage;
Makoto Onuki20c95f82016-05-11 16:51:01 -0700341
342 @Nullable
Makoto Onukibe73a802016-04-15 14:46:35 -0700343 private ArraySet<String> mCategories;
Makoto Onukib6d35232016-04-04 15:57:17 -0700344
Makoto Onuki55046222016-03-08 10:49:47 -0800345 /**
Makoto Onuki440a1ea2016-07-20 14:21:18 -0700346 * Intents *with extras removed*.
Makoto Onuki55046222016-03-08 10:49:47 -0800347 */
Makoto Onuki20c95f82016-05-11 16:51:01 -0700348 @Nullable
Makoto Onuki440a1ea2016-07-20 14:21:18 -0700349 private Intent[] mIntents;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800350
Makoto Onuki55046222016-03-08 10:49:47 -0800351 /**
Makoto Onuki440a1ea2016-07-20 14:21:18 -0700352 * Extras for the intents.
Makoto Onuki55046222016-03-08 10:49:47 -0800353 */
Makoto Onuki20c95f82016-05-11 16:51:01 -0700354 @Nullable
Makoto Onuki440a1ea2016-07-20 14:21:18 -0700355 private PersistableBundle[] mIntentPersistableExtrases;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800356
Mehdi Alizadeh14242af2018-12-20 20:11:35 -0800357 @Nullable
358 private Person[] mPersons;
359
Felipe Leme90205ef2019-03-05 09:59:52 -0800360 @Nullable
361 private LocusId mLocusId;
362
Makoto Onuki20c95f82016-05-11 16:51:01 -0700363 private int mRank;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800364
Makoto Onuki9e1f5592016-06-08 12:30:23 -0700365 /**
366 * Internally used for auto-rank-adjustment.
367 *
368 * RANK_CHANGED_BIT is used to denote that the rank of a shortcut is changing.
369 * The rest of the bits are used to denote the order in which shortcuts are passed to
370 * APIs, which is used to preserve the argument order when ranks are tie.
371 */
372 private int mImplicitRank;
373
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800374 @Nullable
375 private PersistableBundle mExtras;
376
377 private long mLastChangedTimestamp;
378
379 // Internal use only.
380 @ShortcutFlags
381 private int mFlags;
382
383 // Internal use only.
Makoto Onuki157b1622016-06-02 16:13:10 -0700384 private int mIconResId;
385
386 private String mIconResName;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800387
388 // Internal use only.
389 @Nullable
390 private String mBitmapPath;
391
Makoto Onukiabe84422016-04-07 09:41:19 -0700392 private final int mUserId;
393
Makoto Onukia4f89b12017-10-05 10:37:55 -0700394 /** @hide */
395 public static final int VERSION_CODE_UNKNOWN = -1;
396
397 private int mDisabledReason;
398
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800399 private ShortcutInfo(Builder b) {
Makoto Onukiabe84422016-04-07 09:41:19 -0700400 mUserId = b.mContext.getUserId();
401
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800402 mId = Preconditions.checkStringNotEmpty(b.mId, "Shortcut ID must be provided");
403
404 // Note we can't do other null checks here because SM.updateShortcuts() takes partial
405 // information.
406 mPackageName = b.mContext.getPackageName();
Makoto Onuki22fcc682016-05-17 14:52:19 -0700407 mActivity = b.mActivity;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800408 mIcon = b.mIcon;
409 mTitle = b.mTitle;
Makoto Onuki20c95f82016-05-11 16:51:01 -0700410 mTitleResId = b.mTitleResId;
Makoto Onukie3ae7ec2016-03-29 15:45:25 -0700411 mText = b.mText;
Makoto Onuki20c95f82016-05-11 16:51:01 -0700412 mTextResId = b.mTextResId;
413 mDisabledMessage = b.mDisabledMessage;
414 mDisabledMessageResId = b.mDisabledMessageResId;
Makoto Onukidf6da042016-06-16 09:51:40 -0700415 mCategories = cloneCategories(b.mCategories);
Makoto Onuki440a1ea2016-07-20 14:21:18 -0700416 mIntents = cloneIntents(b.mIntents);
417 fixUpIntentExtras();
Mehdi Alizadeh14242af2018-12-20 20:11:35 -0800418 mPersons = clonePersons(b.mPersons);
419 if (b.mIsLongLived) {
420 setLongLived();
421 }
Makoto Onuki20c95f82016-05-11 16:51:01 -0700422 mRank = b.mRank;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800423 mExtras = b.mExtras;
Felipe Leme90205ef2019-03-05 09:59:52 -0800424 mLocusId = b.mLocusId;
425
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800426 updateTimestamp();
427 }
428
Makoto Onuki440a1ea2016-07-20 14:21:18 -0700429 /**
430 * Extract extras from {@link #mIntents} and set them to {@link #mIntentPersistableExtrases}
431 * as {@link PersistableBundle}, and remove extras from the original intents.
432 */
433 private void fixUpIntentExtras() {
434 if (mIntents == null) {
435 mIntentPersistableExtrases = null;
436 return;
437 }
438 mIntentPersistableExtrases = new PersistableBundle[mIntents.length];
439 for (int i = 0; i < mIntents.length; i++) {
440 final Intent intent = mIntents[i];
441 final Bundle extras = intent.getExtras();
442 if (extras == null) {
443 mIntentPersistableExtrases[i] = null;
444 } else {
445 mIntentPersistableExtrases[i] = new PersistableBundle(extras);
446 intent.replaceExtras((Bundle) null);
447 }
448 }
449 }
450
451 private static ArraySet<String> cloneCategories(Set<String> source) {
Makoto Onukidf6da042016-06-16 09:51:40 -0700452 if (source == null) {
453 return null;
454 }
455 final ArraySet<String> ret = new ArraySet<>(source.size());
456 for (CharSequence s : source) {
457 if (!TextUtils.isEmpty(s)) {
458 ret.add(s.toString().intern());
459 }
460 }
461 return ret;
Makoto Onukib6d35232016-04-04 15:57:17 -0700462 }
463
Makoto Onuki440a1ea2016-07-20 14:21:18 -0700464 private static Intent[] cloneIntents(Intent[] intents) {
465 if (intents == null) {
466 return null;
467 }
468 final Intent[] ret = new Intent[intents.length];
469 for (int i = 0; i < ret.length; i++) {
470 if (intents[i] != null) {
471 ret[i] = new Intent(intents[i]);
472 }
473 }
474 return ret;
475 }
476
477 private static PersistableBundle[] clonePersistableBundle(PersistableBundle[] bundle) {
478 if (bundle == null) {
479 return null;
480 }
481 final PersistableBundle[] ret = new PersistableBundle[bundle.length];
482 for (int i = 0; i < ret.length; i++) {
483 if (bundle[i] != null) {
484 ret[i] = new PersistableBundle(bundle[i]);
485 }
486 }
487 return ret;
488 }
489
Mehdi Alizadeh14242af2018-12-20 20:11:35 -0800490 private static Person[] clonePersons(Person[] persons) {
491 if (persons == null) {
492 return null;
493 }
494 final Person[] ret = new Person[persons.length];
495 for (int i = 0; i < ret.length; i++) {
496 if (persons[i] != null) {
497 // Don't need to keep the icon, remove it to save space
498 ret[i] = persons[i].toBuilder().setIcon(null).build();
499 }
500 }
501 return ret;
502 }
503
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800504 /**
505 * Throws if any of the mandatory fields is not set.
506 *
507 * @hide
508 */
Makoto Onuki106ff7a2016-12-01 10:17:57 -0800509 public void enforceMandatoryFields(boolean forPinned) {
Makoto Onukie3ae7ec2016-03-29 15:45:25 -0700510 Preconditions.checkStringNotEmpty(mId, "Shortcut ID must be provided");
Makoto Onuki106ff7a2016-12-01 10:17:57 -0800511 if (!forPinned) {
512 Preconditions.checkNotNull(mActivity, "Activity must be provided");
513 }
Makoto Onuki20c95f82016-05-11 16:51:01 -0700514 if (mTitle == null && mTitleResId == 0) {
Makoto Onukia1d38b32016-06-10 15:32:26 -0700515 throw new IllegalArgumentException("Short label must be provided");
Makoto Onuki20c95f82016-05-11 16:51:01 -0700516 }
Makoto Onuki99302b52017-03-29 12:42:26 -0700517 Preconditions.checkNotNull(mIntents, "Shortcut Intent must be provided");
518 Preconditions.checkArgument(mIntents.length > 0, "Shortcut Intent must be provided");
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800519 }
520
521 /**
522 * Copy constructor.
523 */
524 private ShortcutInfo(ShortcutInfo source, @CloneFlags int cloneFlags) {
Makoto Onukiabe84422016-04-07 09:41:19 -0700525 mUserId = source.mUserId;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800526 mId = source.mId;
527 mPackageName = source.mPackageName;
Makoto Onuki4d6b87f2016-06-17 13:47:40 -0700528 mActivity = source.mActivity;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800529 mFlags = source.mFlags;
530 mLastChangedTimestamp = source.mLastChangedTimestamp;
Makoto Onukia4f89b12017-10-05 10:37:55 -0700531 mDisabledReason = source.mDisabledReason;
Felipe Leme90205ef2019-03-05 09:59:52 -0800532 mLocusId = source.mLocusId;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800533
Makoto Onukib6d35232016-04-04 15:57:17 -0700534 // Just always keep it since it's cheep.
Makoto Onuki157b1622016-06-02 16:13:10 -0700535 mIconResId = source.mIconResId;
Makoto Onukib6d35232016-04-04 15:57:17 -0700536
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800537 if ((cloneFlags & CLONE_REMOVE_NON_KEY_INFO) == 0) {
Makoto Onuki55046222016-03-08 10:49:47 -0800538
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800539 if ((cloneFlags & CLONE_REMOVE_ICON) == 0) {
540 mIcon = source.mIcon;
Makoto Onuki7a6a05f2016-03-10 17:01:08 -0800541 mBitmapPath = source.mBitmapPath;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800542 }
543
544 mTitle = source.mTitle;
Makoto Onuki20c95f82016-05-11 16:51:01 -0700545 mTitleResId = source.mTitleResId;
Makoto Onukie3ae7ec2016-03-29 15:45:25 -0700546 mText = source.mText;
Makoto Onuki20c95f82016-05-11 16:51:01 -0700547 mTextResId = source.mTextResId;
548 mDisabledMessage = source.mDisabledMessage;
549 mDisabledMessageResId = source.mDisabledMessageResId;
Makoto Onukidf6da042016-06-16 09:51:40 -0700550 mCategories = cloneCategories(source.mCategories);
Mehdi Alizadeh14242af2018-12-20 20:11:35 -0800551 mPersons = clonePersons(source.mPersons);
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800552 if ((cloneFlags & CLONE_REMOVE_INTENT) == 0) {
Makoto Onuki440a1ea2016-07-20 14:21:18 -0700553 mIntents = cloneIntents(source.mIntents);
554 mIntentPersistableExtrases =
555 clonePersistableBundle(source.mIntentPersistableExtrases);
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800556 }
Makoto Onuki20c95f82016-05-11 16:51:01 -0700557 mRank = source.mRank;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800558 mExtras = source.mExtras;
Makoto Onuki157b1622016-06-02 16:13:10 -0700559
560 if ((cloneFlags & CLONE_REMOVE_RES_NAMES) == 0) {
561 mTitleResName = source.mTitleResName;
562 mTextResName = source.mTextResName;
563 mDisabledMessageResName = source.mDisabledMessageResName;
564 mIconResName = source.mIconResName;
565 }
Makoto Onuki55046222016-03-08 10:49:47 -0800566 } else {
567 // Set this bit.
568 mFlags |= FLAG_KEY_FIELDS_ONLY;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800569 }
570 }
571
Makoto Onuki157b1622016-06-02 16:13:10 -0700572 /**
573 * Load a string resource from the publisher app.
574 *
575 * @param resId resource ID
576 * @param defValue default value to be returned when the specified resource isn't found.
577 */
578 private CharSequence getResourceString(Resources res, int resId, CharSequence defValue) {
579 try {
580 return res.getString(resId);
581 } catch (NotFoundException e) {
582 Log.e(TAG, "Resource for ID=" + resId + " not found in package " + mPackageName);
583 return defValue;
584 }
585 }
586
587 /**
588 * Load the string resources for the text fields and set them to the actual value fields.
589 * This will set {@link #FLAG_STRINGS_RESOLVED}.
590 *
591 * @param res {@link Resources} for the publisher. Must have been loaded with
592 * {@link PackageManager#getResourcesForApplicationAsUser}.
593 *
594 * @hide
595 */
596 public void resolveResourceStrings(@NonNull Resources res) {
Makoto Onuki20c95f82016-05-11 16:51:01 -0700597 mFlags |= FLAG_STRINGS_RESOLVED;
598
599 if ((mTitleResId == 0) && (mTextResId == 0) && (mDisabledMessageResId == 0)) {
600 return; // Bail early.
601 }
Makoto Onuki20c95f82016-05-11 16:51:01 -0700602
603 if (mTitleResId != 0) {
Makoto Onuki157b1622016-06-02 16:13:10 -0700604 mTitle = getResourceString(res, mTitleResId, mTitle);
Makoto Onuki20c95f82016-05-11 16:51:01 -0700605 }
606 if (mTextResId != 0) {
Makoto Onuki157b1622016-06-02 16:13:10 -0700607 mText = getResourceString(res, mTextResId, mText);
Makoto Onuki20c95f82016-05-11 16:51:01 -0700608 }
609 if (mDisabledMessageResId != 0) {
Makoto Onuki157b1622016-06-02 16:13:10 -0700610 mDisabledMessage = getResourceString(res, mDisabledMessageResId, mDisabledMessage);
Makoto Onuki20c95f82016-05-11 16:51:01 -0700611 }
612 }
613
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800614 /**
Makoto Onuki157b1622016-06-02 16:13:10 -0700615 * Look up resource name for a given resource ID.
616 *
617 * @return a simple resource name (e.g. "text_1") when {@code withType} is false, or with the
618 * type (e.g. "string/text_1").
619 *
620 * @hide
621 */
622 @VisibleForTesting
623 public static String lookUpResourceName(@NonNull Resources res, int resId, boolean withType,
624 @NonNull String packageName) {
625 if (resId == 0) {
626 return null;
627 }
628 try {
629 final String fullName = res.getResourceName(resId);
630
631 if (ANDROID_PACKAGE_NAME.equals(getResourcePackageName(fullName))) {
632 // If it's a framework resource, the value won't change, so just return the ID
633 // value as a string.
634 return String.valueOf(resId);
635 }
636 return withType ? getResourceTypeAndEntryName(fullName)
637 : getResourceEntryName(fullName);
638 } catch (NotFoundException e) {
639 Log.e(TAG, "Resource name for ID=" + resId + " not found in package " + packageName
640 + ". Resource IDs may change when the application is upgraded, and the system"
641 + " may not be able to find the correct resource.");
642 return null;
643 }
644 }
645
646 /**
647 * Extract the package name from a fully-donated resource name.
648 * e.g. "com.android.app1:drawable/icon1" -> "com.android.app1"
649 * @hide
650 */
651 @VisibleForTesting
652 public static String getResourcePackageName(@NonNull String fullResourceName) {
653 final int p1 = fullResourceName.indexOf(':');
654 if (p1 < 0) {
655 return null;
656 }
657 return fullResourceName.substring(0, p1);
658 }
659
660 /**
661 * Extract the type name from a fully-donated resource name.
662 * e.g. "com.android.app1:drawable/icon1" -> "drawable"
663 * @hide
664 */
665 @VisibleForTesting
666 public static String getResourceTypeName(@NonNull String fullResourceName) {
667 final int p1 = fullResourceName.indexOf(':');
668 if (p1 < 0) {
669 return null;
670 }
671 final int p2 = fullResourceName.indexOf('/', p1 + 1);
672 if (p2 < 0) {
673 return null;
674 }
675 return fullResourceName.substring(p1 + 1, p2);
676 }
677
678 /**
679 * Extract the type name + the entry name from a fully-donated resource name.
680 * e.g. "com.android.app1:drawable/icon1" -> "drawable/icon1"
681 * @hide
682 */
683 @VisibleForTesting
684 public static String getResourceTypeAndEntryName(@NonNull String fullResourceName) {
685 final int p1 = fullResourceName.indexOf(':');
686 if (p1 < 0) {
687 return null;
688 }
689 return fullResourceName.substring(p1 + 1);
690 }
691
692 /**
693 * Extract the entry name from a fully-donated resource name.
694 * e.g. "com.android.app1:drawable/icon1" -> "icon1"
695 * @hide
696 */
697 @VisibleForTesting
698 public static String getResourceEntryName(@NonNull String fullResourceName) {
699 final int p1 = fullResourceName.indexOf('/');
700 if (p1 < 0) {
701 return null;
702 }
703 return fullResourceName.substring(p1 + 1);
704 }
705
706 /**
707 * Return the resource ID for a given resource ID.
708 *
709 * Basically its' a wrapper over {@link Resources#getIdentifier(String, String, String)}, except
710 * if {@code resourceName} is an integer then it'll just return its value. (Which also the
711 * aforementioned method would do internally, but not documented, so doing here explicitly.)
712 *
713 * @param res {@link Resources} for the publisher. Must have been loaded with
714 * {@link PackageManager#getResourcesForApplicationAsUser}.
715 *
716 * @hide
717 */
718 @VisibleForTesting
719 public static int lookUpResourceId(@NonNull Resources res, @Nullable String resourceName,
720 @Nullable String resourceType, String packageName) {
721 if (resourceName == null) {
722 return 0;
723 }
724 try {
725 try {
726 // It the name can be parsed as an integer, just use it.
727 return Integer.parseInt(resourceName);
728 } catch (NumberFormatException ignore) {
729 }
730
731 return res.getIdentifier(resourceName, resourceType, packageName);
732 } catch (NotFoundException e) {
733 Log.e(TAG, "Resource ID for name=" + resourceName + " not found in package "
734 + packageName);
735 return 0;
736 }
737 }
738
739 /**
740 * Look up resource names from the resource IDs for the icon res and the text fields, and fill
741 * in the resource name fields.
742 *
743 * @param res {@link Resources} for the publisher. Must have been loaded with
744 * {@link PackageManager#getResourcesForApplicationAsUser}.
745 *
746 * @hide
747 */
748 public void lookupAndFillInResourceNames(@NonNull Resources res) {
749 if ((mTitleResId == 0) && (mTextResId == 0) && (mDisabledMessageResId == 0)
750 && (mIconResId == 0)) {
751 return; // Bail early.
752 }
753
754 // We don't need types for strings because their types are always "string".
755 mTitleResName = lookUpResourceName(res, mTitleResId, /*withType=*/ false, mPackageName);
756 mTextResName = lookUpResourceName(res, mTextResId, /*withType=*/ false, mPackageName);
757 mDisabledMessageResName = lookUpResourceName(res, mDisabledMessageResId,
758 /*withType=*/ false, mPackageName);
759
760 // But icons have multiple possible types, so include the type.
761 mIconResName = lookUpResourceName(res, mIconResId, /*withType=*/ true, mPackageName);
762 }
763
764 /**
765 * Look up resource IDs from the resource names for the icon res and the text fields, and fill
766 * in the resource ID fields.
767 *
768 * This is called when an app is updated.
769 *
770 * @hide
771 */
772 public void lookupAndFillInResourceIds(@NonNull Resources res) {
773 if ((mTitleResName == null) && (mTextResName == null) && (mDisabledMessageResName == null)
774 && (mIconResName == null)) {
775 return; // Bail early.
776 }
777
778 mTitleResId = lookUpResourceId(res, mTitleResName, RES_TYPE_STRING, mPackageName);
779 mTextResId = lookUpResourceId(res, mTextResName, RES_TYPE_STRING, mPackageName);
780 mDisabledMessageResId = lookUpResourceId(res, mDisabledMessageResName, RES_TYPE_STRING,
781 mPackageName);
782
783 // mIconResName already contains the type, so the third argument is not needed.
784 mIconResId = lookUpResourceId(res, mIconResName, null, mPackageName);
785 }
786
787 /**
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800788 * Copy a {@link ShortcutInfo}, optionally removing fields.
789 * @hide
790 */
791 public ShortcutInfo clone(@CloneFlags int cloneFlags) {
792 return new ShortcutInfo(this, cloneFlags);
793 }
794
795 /**
Makoto Onuki22fcc682016-05-17 14:52:19 -0700796 * @hide
Makoto Onukia4f89b12017-10-05 10:37:55 -0700797 *
798 * @isUpdating set true if it's "update", as opposed to "replace".
Makoto Onuki22fcc682016-05-17 14:52:19 -0700799 */
Makoto Onukia4f89b12017-10-05 10:37:55 -0700800 public void ensureUpdatableWith(ShortcutInfo source, boolean isUpdating) {
801 if (isUpdating) {
802 Preconditions.checkState(isVisibleToPublisher(),
803 "[Framework BUG] Invisible shortcuts can't be updated");
804 }
Makoto Onuki22fcc682016-05-17 14:52:19 -0700805 Preconditions.checkState(mUserId == source.mUserId, "Owner User ID must match");
806 Preconditions.checkState(mId.equals(source.mId), "ID must match");
807 Preconditions.checkState(mPackageName.equals(source.mPackageName),
808 "Package name must match");
Makoto Onukia4f89b12017-10-05 10:37:55 -0700809
810 if (isVisibleToPublisher()) {
811 // Don't do this check for restore-blocked shortcuts.
812 Preconditions.checkState(!isImmutable(), "Target ShortcutInfo is immutable");
813 }
Makoto Onuki22fcc682016-05-17 14:52:19 -0700814 }
815
816 /**
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800817 * Copy non-null/zero fields from another {@link ShortcutInfo}. Only "public" information
Makoto Onuki9e1f5592016-06-08 12:30:23 -0700818 * will be overwritten. The timestamp will *not* be updated to be consistent with other
819 * setters (and also the clock is not injectable in this file).
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800820 *
821 * - Flags will not change
822 * - mBitmapPath will not change
823 * - Current time will be set to timestamp
824 *
Makoto Onuki22fcc682016-05-17 14:52:19 -0700825 * @throws IllegalStateException if source is not compatible.
826 *
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800827 * @hide
828 */
829 public void copyNonNullFieldsFrom(ShortcutInfo source) {
Makoto Onukia4f89b12017-10-05 10:37:55 -0700830 ensureUpdatableWith(source, /*isUpdating=*/ true);
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800831
Makoto Onuki22fcc682016-05-17 14:52:19 -0700832 if (source.mActivity != null) {
833 mActivity = source.mActivity;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800834 }
835
836 if (source.mIcon != null) {
837 mIcon = source.mIcon;
Makoto Onuki157b1622016-06-02 16:13:10 -0700838
839 mIconResId = 0;
840 mIconResName = null;
841 mBitmapPath = null;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800842 }
843 if (source.mTitle != null) {
844 mTitle = source.mTitle;
Makoto Onuki20c95f82016-05-11 16:51:01 -0700845 mTitleResId = 0;
Makoto Onuki157b1622016-06-02 16:13:10 -0700846 mTitleResName = null;
Makoto Onuki20c95f82016-05-11 16:51:01 -0700847 } else if (source.mTitleResId != 0) {
848 mTitle = null;
Makoto Onukieddbfec2016-05-31 17:04:34 -0700849 mTitleResId = source.mTitleResId;
Makoto Onuki157b1622016-06-02 16:13:10 -0700850 mTitleResName = null;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800851 }
Makoto Onuki157b1622016-06-02 16:13:10 -0700852
Makoto Onukie3ae7ec2016-03-29 15:45:25 -0700853 if (source.mText != null) {
854 mText = source.mText;
Makoto Onuki20c95f82016-05-11 16:51:01 -0700855 mTextResId = 0;
Makoto Onuki157b1622016-06-02 16:13:10 -0700856 mTextResName = null;
Makoto Onuki20c95f82016-05-11 16:51:01 -0700857 } else if (source.mTextResId != 0) {
858 mText = null;
859 mTextResId = source.mTextResId;
Makoto Onuki157b1622016-06-02 16:13:10 -0700860 mTextResName = null;
Makoto Onuki20c95f82016-05-11 16:51:01 -0700861 }
862 if (source.mDisabledMessage != null) {
863 mDisabledMessage = source.mDisabledMessage;
864 mDisabledMessageResId = 0;
Makoto Onuki157b1622016-06-02 16:13:10 -0700865 mDisabledMessageResName = null;
Makoto Onuki20c95f82016-05-11 16:51:01 -0700866 } else if (source.mDisabledMessageResId != 0) {
867 mDisabledMessage = null;
868 mDisabledMessageResId = source.mDisabledMessageResId;
Makoto Onuki157b1622016-06-02 16:13:10 -0700869 mDisabledMessageResName = null;
Makoto Onukie3ae7ec2016-03-29 15:45:25 -0700870 }
Makoto Onukib6d35232016-04-04 15:57:17 -0700871 if (source.mCategories != null) {
Makoto Onukidf6da042016-06-16 09:51:40 -0700872 mCategories = cloneCategories(source.mCategories);
Makoto Onukib6d35232016-04-04 15:57:17 -0700873 }
Mehdi Alizadeh14242af2018-12-20 20:11:35 -0800874 if (source.mPersons != null) {
875 mPersons = clonePersons(source.mPersons);
876 }
Makoto Onuki440a1ea2016-07-20 14:21:18 -0700877 if (source.mIntents != null) {
878 mIntents = cloneIntents(source.mIntents);
879 mIntentPersistableExtrases =
880 clonePersistableBundle(source.mIntentPersistableExtrases);
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800881 }
Makoto Onuki9e1f5592016-06-08 12:30:23 -0700882 if (source.mRank != RANK_NOT_SET) {
Makoto Onuki20c95f82016-05-11 16:51:01 -0700883 mRank = source.mRank;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800884 }
885 if (source.mExtras != null) {
886 mExtras = source.mExtras;
887 }
Felipe Leme90205ef2019-03-05 09:59:52 -0800888
889 if (source.mLocusId != null) {
890 mLocusId = source.mLocusId;
891 }
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800892 }
893
894 /**
Makoto Onuki55046222016-03-08 10:49:47 -0800895 * @hide
896 */
897 public static Icon validateIcon(Icon icon) {
898 switch (icon.getType()) {
899 case Icon.TYPE_RESOURCE:
900 case Icon.TYPE_BITMAP:
Hyunyoung Songe4179e22017-03-01 12:51:26 -0800901 case Icon.TYPE_ADAPTIVE_BITMAP:
Makoto Onuki55046222016-03-08 10:49:47 -0800902 break; // OK
Makoto Onuki55046222016-03-08 10:49:47 -0800903 default:
904 throw getInvalidIconException();
905 }
906 if (icon.hasTint()) {
Makoto Onuki55046222016-03-08 10:49:47 -0800907 throw new IllegalArgumentException("Icons with tints are not supported");
908 }
909
910 return icon;
911 }
912
913 /** @hide */
914 public static IllegalArgumentException getInvalidIconException() {
915 return new IllegalArgumentException("Unsupported icon type:"
Makoto Onukia97256b2016-07-15 13:23:54 -0700916 +" only the bitmap and resource types are supported");
Makoto Onuki55046222016-03-08 10:49:47 -0800917 }
918
919 /**
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800920 * Builder class for {@link ShortcutInfo} objects.
Makoto Onuki4a910962016-07-07 13:57:34 -0700921 *
922 * @see ShortcutManager
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800923 */
924 public static class Builder {
925 private final Context mContext;
926
927 private String mId;
928
Makoto Onuki22fcc682016-05-17 14:52:19 -0700929 private ComponentName mActivity;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800930
931 private Icon mIcon;
932
Makoto Onuki20c95f82016-05-11 16:51:01 -0700933 private int mTitleResId;
934
Makoto Onuki22fcc682016-05-17 14:52:19 -0700935 private CharSequence mTitle;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800936
Makoto Onuki20c95f82016-05-11 16:51:01 -0700937 private int mTextResId;
938
Makoto Onuki22fcc682016-05-17 14:52:19 -0700939 private CharSequence mText;
Makoto Onukie3ae7ec2016-03-29 15:45:25 -0700940
Makoto Onuki20c95f82016-05-11 16:51:01 -0700941 private int mDisabledMessageResId;
942
Makoto Onuki22fcc682016-05-17 14:52:19 -0700943 private CharSequence mDisabledMessage;
Makoto Onuki20c95f82016-05-11 16:51:01 -0700944
Makoto Onukibe73a802016-04-15 14:46:35 -0700945 private Set<String> mCategories;
Makoto Onukib6d35232016-04-04 15:57:17 -0700946
Makoto Onuki440a1ea2016-07-20 14:21:18 -0700947 private Intent[] mIntents;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800948
Mehdi Alizadeh14242af2018-12-20 20:11:35 -0800949 private Person[] mPersons;
950
951 private boolean mIsLongLived;
952
Makoto Onuki9e1f5592016-06-08 12:30:23 -0700953 private int mRank = RANK_NOT_SET;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800954
955 private PersistableBundle mExtras;
956
Felipe Leme90205ef2019-03-05 09:59:52 -0800957 private LocusId mLocusId;
958
Makoto Onukib5a012f2016-06-21 11:13:53 -0700959 /**
Makoto Onuki598aca42016-07-06 16:05:03 -0700960 * Old style constructor.
961 * @hide
Makoto Onukib5a012f2016-06-21 11:13:53 -0700962 */
963 @Deprecated
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800964 public Builder(Context context) {
965 mContext = context;
966 }
967
968 /**
Makoto Onuki598aca42016-07-06 16:05:03 -0700969 * Used with the old style constructor, kept for unit tests.
970 * @hide
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800971 */
972 @NonNull
Makoto Onukib5a012f2016-06-21 11:13:53 -0700973 @Deprecated
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800974 public Builder setId(@NonNull String id) {
Makoto Onukib08790c2016-06-23 14:05:46 -0700975 mId = Preconditions.checkStringNotEmpty(id, "id cannot be empty");
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800976 return this;
977 }
978
979 /**
Makoto Onukib5a012f2016-06-21 11:13:53 -0700980 * Constructor.
981 *
982 * @param context Client context.
983 * @param id ID of the shortcut.
984 */
985 public Builder(Context context, String id) {
986 mContext = context;
Makoto Onukib08790c2016-06-23 14:05:46 -0700987 mId = Preconditions.checkStringNotEmpty(id, "id cannot be empty");
Makoto Onukib5a012f2016-06-21 11:13:53 -0700988 }
989
990 /**
Felipe Leme90205ef2019-03-05 09:59:52 -0800991 * Sets the {@link LocusId} associated with this shortcut.
992 *
993 * <p>This method should be called when the {@link LocusId} is used in other places (such
994 * as {@link Notification} and {@link ContentCaptureContext}) so the device's intelligence
995 * services can correlate them.
996 */
997 @NonNull
998 public Builder setLocusId(@NonNull LocusId locusId) {
999 mLocusId = Preconditions.checkNotNull(locusId, "locusId cannot be null");
1000 return this;
1001 }
1002
1003 /**
Makoto Onuki4a910962016-07-07 13:57:34 -07001004 * Sets the target activity. A shortcut will be shown along with this activity's icon
1005 * on the launcher.
Makoto Onukib5a012f2016-06-21 11:13:53 -07001006 *
Makoto Onukife9c9662016-07-25 15:12:23 -07001007 * When selecting a target activity, keep the following in mind:
Makoto Onuki4a910962016-07-07 13:57:34 -07001008 * <ul>
Makoto Onukife9c9662016-07-25 15:12:23 -07001009 * <li>All dynamic shortcuts must have a target activity. When a shortcut with no target
1010 * activity is published using
1011 * {@link ShortcutManager#addDynamicShortcuts(List)} or
1012 * {@link ShortcutManager#setDynamicShortcuts(List)},
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001013 * the first main activity defined in the app's <code>AndroidManifest.xml</code>
Makoto Onukife9c9662016-07-25 15:12:23 -07001014 * file is used.
1015 *
1016 * <li>Only "main" activities&mdash;ones that define the {@link Intent#ACTION_MAIN}
1017 * and {@link Intent#CATEGORY_LAUNCHER} intent filters&mdash;can be target
Makoto Onuki4a910962016-07-07 13:57:34 -07001018 * activities.
1019 *
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001020 * <li>By default, the first main activity defined in the app's manifest is
Makoto Onukife9c9662016-07-25 15:12:23 -07001021 * the target activity.
Makoto Onuki4d36b3a2016-04-27 12:00:17 -07001022 *
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001023 * <li>A target activity must belong to the publisher app.
Makoto Onuki4a910962016-07-07 13:57:34 -07001024 * </ul>
Makoto Onuki4d36b3a2016-04-27 12:00:17 -07001025 *
Makoto Onuki4a910962016-07-07 13:57:34 -07001026 * @see ShortcutInfo#getActivity()
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001027 */
1028 @NonNull
Makoto Onuki22fcc682016-05-17 14:52:19 -07001029 public Builder setActivity(@NonNull ComponentName activity) {
Makoto Onukib08790c2016-06-23 14:05:46 -07001030 mActivity = Preconditions.checkNotNull(activity, "activity cannot be null");
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001031 return this;
1032 }
1033
1034 /**
Makoto Onuki4a910962016-07-07 13:57:34 -07001035 * Sets an icon of a shortcut.
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001036 *
Makoto Onuki4a910962016-07-07 13:57:34 -07001037 * <p>Icons are not available on {@link ShortcutInfo} instances
1038 * returned by {@link ShortcutManager} or {@link LauncherApps}. The default launcher
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001039 * app can use {@link LauncherApps#getShortcutIconDrawable(ShortcutInfo, int)}
Makoto Onukib5a012f2016-06-21 11:13:53 -07001040 * or {@link LauncherApps#getShortcutBadgedIconDrawable(ShortcutInfo, int)} to fetch
1041 * shortcut icons.
Makoto Onuki4a910962016-07-07 13:57:34 -07001042 *
1043 * <p>Tints set with {@link Icon#setTint} or {@link Icon#setTintList} are not supported
1044 * and will be ignored.
1045 *
Hyunyoung Songf281e7a2017-02-13 10:57:42 -08001046 * <p>Only icons created with {@link Icon#createWithBitmap(Bitmap)},
Hyunyoung Songe4179e22017-03-01 12:51:26 -08001047 * {@link Icon#createWithAdaptiveBitmap(Bitmap)}
Hyunyoung Songf281e7a2017-02-13 10:57:42 -08001048 * and {@link Icon#createWithResource} are supported.
Makoto Onukife9c9662016-07-25 15:12:23 -07001049 * Other types, such as URI-based icons, are not supported.
Makoto Onuki4a910962016-07-07 13:57:34 -07001050 *
1051 * @see LauncherApps#getShortcutIconDrawable(ShortcutInfo, int)
1052 * @see LauncherApps#getShortcutBadgedIconDrawable(ShortcutInfo, int)
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001053 */
1054 @NonNull
1055 public Builder setIcon(Icon icon) {
Makoto Onuki55046222016-03-08 10:49:47 -08001056 mIcon = validateIcon(icon);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001057 return this;
1058 }
1059
Makoto Onukieddbfec2016-05-31 17:04:34 -07001060 /**
1061 * @hide We don't support resource strings for dynamic shortcuts for now. (But unit tests
1062 * use it.)
1063 */
Makoto Onukib5a012f2016-06-21 11:13:53 -07001064 @Deprecated
Makoto Onukieddbfec2016-05-31 17:04:34 -07001065 public Builder setShortLabelResId(int shortLabelResId) {
1066 Preconditions.checkState(mTitle == null, "shortLabel already set");
1067 mTitleResId = shortLabelResId;
Makoto Onuki20c95f82016-05-11 16:51:01 -07001068 return this;
1069 }
1070
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001071 /**
Makoto Onukib5a012f2016-06-21 11:13:53 -07001072 * Sets the short title of a shortcut.
1073 *
Makoto Onuki4a910962016-07-07 13:57:34 -07001074 * <p>This is a mandatory field when publishing a new shortcut with
1075 * {@link ShortcutManager#addDynamicShortcuts(List)} or
1076 * {@link ShortcutManager#setDynamicShortcuts(List)}.
Makoto Onuki0e65d362016-03-29 14:46:50 -07001077 *
Makoto Onukife9c9662016-07-25 15:12:23 -07001078 * <p>This field is intended to be a concise description of a shortcut.
Makoto Onuki4a910962016-07-07 13:57:34 -07001079 *
Makoto Onukife9c9662016-07-25 15:12:23 -07001080 * <p>The recommended maximum length is 10 characters.
Makoto Onuki4a910962016-07-07 13:57:34 -07001081 *
1082 * @see ShortcutInfo#getShortLabel()
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001083 */
1084 @NonNull
Makoto Onukidf6da042016-06-16 09:51:40 -07001085 public Builder setShortLabel(@NonNull CharSequence shortLabel) {
Makoto Onukieddbfec2016-05-31 17:04:34 -07001086 Preconditions.checkState(mTitleResId == 0, "shortLabelResId already set");
Makoto Onukib08790c2016-06-23 14:05:46 -07001087 mTitle = Preconditions.checkStringNotEmpty(shortLabel, "shortLabel cannot be empty");
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001088 return this;
1089 }
1090
Makoto Onukieddbfec2016-05-31 17:04:34 -07001091 /**
1092 * @hide We don't support resource strings for dynamic shortcuts for now. (But unit tests
1093 * use it.)
1094 */
Makoto Onukib5a012f2016-06-21 11:13:53 -07001095 @Deprecated
Makoto Onukieddbfec2016-05-31 17:04:34 -07001096 public Builder setLongLabelResId(int longLabelResId) {
1097 Preconditions.checkState(mText == null, "longLabel already set");
1098 mTextResId = longLabelResId;
Makoto Onuki20c95f82016-05-11 16:51:01 -07001099 return this;
1100 }
1101
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001102 /**
Makoto Onukib5a012f2016-06-21 11:13:53 -07001103 * Sets the text of a shortcut.
Makoto Onuki0e65d362016-03-29 14:46:50 -07001104 *
Makoto Onukieddbfec2016-05-31 17:04:34 -07001105 * <p>This field is intended to be more descriptive than the shortcut title. The launcher
Makoto Onuki4a910962016-07-07 13:57:34 -07001106 * shows this instead of the short title when it has enough space.
1107 *
Makoto Onukife9c9662016-07-25 15:12:23 -07001108 * <p>The recommend maximum length is 25 characters.
Makoto Onuki4a910962016-07-07 13:57:34 -07001109 *
1110 * @see ShortcutInfo#getLongLabel()
Makoto Onukie3ae7ec2016-03-29 15:45:25 -07001111 */
1112 @NonNull
Makoto Onukidf6da042016-06-16 09:51:40 -07001113 public Builder setLongLabel(@NonNull CharSequence longLabel) {
Makoto Onukieddbfec2016-05-31 17:04:34 -07001114 Preconditions.checkState(mTextResId == 0, "longLabelResId already set");
Makoto Onukib08790c2016-06-23 14:05:46 -07001115 mText = Preconditions.checkStringNotEmpty(longLabel, "longLabel cannot be empty");
Makoto Onukie3ae7ec2016-03-29 15:45:25 -07001116 return this;
1117 }
1118
Makoto Onukieddbfec2016-05-31 17:04:34 -07001119 /** @hide -- old signature, the internal code still uses it. */
Makoto Onukib5a012f2016-06-21 11:13:53 -07001120 @Deprecated
Makoto Onukidf6da042016-06-16 09:51:40 -07001121 public Builder setTitle(@NonNull CharSequence value) {
Makoto Onukieddbfec2016-05-31 17:04:34 -07001122 return setShortLabel(value);
1123 }
1124
1125 /** @hide -- old signature, the internal code still uses it. */
Makoto Onukib5a012f2016-06-21 11:13:53 -07001126 @Deprecated
Makoto Onukieddbfec2016-05-31 17:04:34 -07001127 public Builder setTitleResId(int value) {
1128 return setShortLabelResId(value);
1129 }
1130
1131 /** @hide -- old signature, the internal code still uses it. */
Makoto Onukib5a012f2016-06-21 11:13:53 -07001132 @Deprecated
Makoto Onukidf6da042016-06-16 09:51:40 -07001133 public Builder setText(@NonNull CharSequence value) {
Makoto Onukieddbfec2016-05-31 17:04:34 -07001134 return setLongLabel(value);
1135 }
1136
1137 /** @hide -- old signature, the internal code still uses it. */
Makoto Onukib5a012f2016-06-21 11:13:53 -07001138 @Deprecated
Makoto Onukieddbfec2016-05-31 17:04:34 -07001139 public Builder setTextResId(int value) {
1140 return setLongLabelResId(value);
1141 }
1142
1143 /**
1144 * @hide We don't support resource strings for dynamic shortcuts for now. (But unit tests
1145 * use it.)
1146 */
Makoto Onukib5a012f2016-06-21 11:13:53 -07001147 @Deprecated
Makoto Onuki20c95f82016-05-11 16:51:01 -07001148 public Builder setDisabledMessageResId(int disabledMessageResId) {
1149 Preconditions.checkState(mDisabledMessage == null, "disabledMessage already set");
1150 mDisabledMessageResId = disabledMessageResId;
1151 return this;
1152 }
1153
Makoto Onuki4a910962016-07-07 13:57:34 -07001154 /**
Makoto Onukife9c9662016-07-25 15:12:23 -07001155 * Sets the message that should be shown when the user attempts to start a shortcut that
1156 * is disabled.
Makoto Onuki4a910962016-07-07 13:57:34 -07001157 *
1158 * @see ShortcutInfo#getDisabledMessage()
1159 */
Makoto Onuki20c95f82016-05-11 16:51:01 -07001160 @NonNull
Makoto Onukidf6da042016-06-16 09:51:40 -07001161 public Builder setDisabledMessage(@NonNull CharSequence disabledMessage) {
Makoto Onuki20c95f82016-05-11 16:51:01 -07001162 Preconditions.checkState(
1163 mDisabledMessageResId == 0, "disabledMessageResId already set");
1164 mDisabledMessage =
Makoto Onukib08790c2016-06-23 14:05:46 -07001165 Preconditions.checkStringNotEmpty(disabledMessage,
1166 "disabledMessage cannot be empty");
Makoto Onuki20c95f82016-05-11 16:51:01 -07001167 return this;
1168 }
1169
Makoto Onukie3ae7ec2016-03-29 15:45:25 -07001170 /**
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001171 * Sets categories for a shortcut. Launcher apps may use this information to
1172 * categorize shortcuts.
Makoto Onukib6d35232016-04-04 15:57:17 -07001173 *
1174 * @see #SHORTCUT_CATEGORY_CONVERSATION
Makoto Onuki4a910962016-07-07 13:57:34 -07001175 * @see ShortcutInfo#getCategories()
Makoto Onukib6d35232016-04-04 15:57:17 -07001176 */
1177 @NonNull
Makoto Onukibe73a802016-04-15 14:46:35 -07001178 public Builder setCategories(Set<String> categories) {
Makoto Onukib6d35232016-04-04 15:57:17 -07001179 mCategories = categories;
1180 return this;
1181 }
1182
1183 /**
Makoto Onuki0eed4412016-07-21 11:21:59 -07001184 * Sets the intent of a shortcut. Alternatively, {@link #setIntents(Intent[])} can be used
1185 * to launch an activity with other activities in the back stack.
Makoto Onuki4a910962016-07-07 13:57:34 -07001186 *
1187 * <p>This is a mandatory field when publishing a new shortcut with
1188 * {@link ShortcutManager#addDynamicShortcuts(List)} or
1189 * {@link ShortcutManager#setDynamicShortcuts(List)}.
1190 *
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001191 * <p>A shortcut can launch any intent that the publisher app has permission to
Makoto Onukife9c9662016-07-25 15:12:23 -07001192 * launch. For example, a shortcut can launch an unexported activity within the publisher
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001193 * app. A shortcut intent doesn't have to point at the target activity.
Makoto Onuki4a910962016-07-07 13:57:34 -07001194 *
Makoto Onukife9c9662016-07-25 15:12:23 -07001195 * <p>The given {@code intent} can contain extras, but these extras must contain values
1196 * of primitive types in order for the system to persist these values.
Makoto Onuki4a910962016-07-07 13:57:34 -07001197 *
1198 * @see ShortcutInfo#getIntent()
Makoto Onuki440a1ea2016-07-20 14:21:18 -07001199 * @see #setIntents(Intent[])
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001200 */
1201 @NonNull
1202 public Builder setIntent(@NonNull Intent intent) {
Makoto Onuki440a1ea2016-07-20 14:21:18 -07001203 return setIntents(new Intent[]{intent});
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001204 }
1205
1206 /**
Makoto Onuki0eed4412016-07-21 11:21:59 -07001207 * Sets multiple intents instead of a single intent, in order to launch an activity with
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001208 * other activities in back stack. Use {@link TaskStackBuilder} to build intents. The
1209 * last element in the list represents the only intent that doesn't place an activity on
1210 * the back stack.
Makoto Onuki0eed4412016-07-21 11:21:59 -07001211 * See the {@link ShortcutManager} javadoc for details.
Makoto Onuki347a6bd2016-07-19 11:13:08 -07001212 *
1213 * @see Builder#setIntent(Intent)
1214 * @see ShortcutInfo#getIntents()
1215 * @see Context#startActivities(Intent[])
1216 * @see TaskStackBuilder
1217 */
1218 @NonNull
1219 public Builder setIntents(@NonNull Intent[] intents) {
Makoto Onuki440a1ea2016-07-20 14:21:18 -07001220 Preconditions.checkNotNull(intents, "intents cannot be null");
1221 Preconditions.checkNotNull(intents.length, "intents cannot be empty");
1222 for (Intent intent : intents) {
1223 Preconditions.checkNotNull(intent, "intents cannot contain null");
1224 Preconditions.checkNotNull(intent.getAction(), "intent's action must be set");
1225 }
1226 // Make sure always clone incoming intents.
1227 mIntents = cloneIntents(intents);
1228 return this;
Makoto Onuki347a6bd2016-07-19 11:13:08 -07001229 }
1230
1231 /**
Mehdi Alizadeh14242af2018-12-20 20:11:35 -08001232 * Add a person that is relevant to this shortcut. Alternatively,
1233 * {@link #setPersons(Person[])} can be used to add multiple persons to a shortcut.
1234 *
1235 * <p> This is an optional field, but the addition of person may cause this shortcut to
1236 * appear more prominently in the user interface (e.g. ShareSheet).
1237 *
1238 * <p> A person should usually contain a uri in order to benefit from the ranking boost.
1239 * However, even if no uri is provided, it's beneficial to provide people in the shortcut,
1240 * such that listeners and voice only devices can announce and handle them properly.
1241 *
1242 * @see Person
1243 * @see #setPersons(Person[])
1244 */
1245 @NonNull
1246 public Builder setPerson(@NonNull Person person) {
1247 return setPersons(new Person[]{person});
1248 }
1249
1250 /**
1251 * Sets multiple persons instead of a single person.
1252 *
1253 * @see Person
1254 * @see #setPerson(Person)
1255 */
1256 @NonNull
1257 public Builder setPersons(@NonNull Person[] persons) {
1258 Preconditions.checkNotNull(persons, "persons cannot be null");
1259 Preconditions.checkNotNull(persons.length, "persons cannot be empty");
1260 for (Person person : persons) {
1261 Preconditions.checkNotNull(person, "persons cannot contain null");
1262 }
1263 mPersons = clonePersons(persons);
1264 return this;
1265 }
1266
1267 /**
1268 * Sets if a shortcut would be valid even if it has been unpublished/invisible by the app
1269 * (as a dynamic or pinned shortcut). If it is long lived, it can be cached by various
1270 * system services even after it has been unpublished as a dynamic shortcut.
1271 */
1272 @NonNull
1273 public Builder setLongLived() {
1274 mIsLongLived = true;
1275 return this;
1276 }
1277
1278 /**
Makoto Onuki9e1f5592016-06-08 12:30:23 -07001279 * "Rank" of a shortcut, which is a non-negative value that's used by the launcher app
1280 * to sort shortcuts.
Makoto Onuki4a910962016-07-07 13:57:34 -07001281 *
1282 * See {@link ShortcutInfo#getRank()} for details.
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001283 */
1284 @NonNull
Makoto Onuki20c95f82016-05-11 16:51:01 -07001285 public Builder setRank(int rank) {
Makoto Onuki9e1f5592016-06-08 12:30:23 -07001286 Preconditions.checkArgument((0 <= rank),
1287 "Rank cannot be negative or bigger than MAX_RANK");
Makoto Onuki20c95f82016-05-11 16:51:01 -07001288 mRank = rank;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001289 return this;
1290 }
1291
1292 /**
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001293 * Extras that the app can set for any purpose.
Makoto Onukib5a012f2016-06-21 11:13:53 -07001294 *
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001295 * <p>Apps can store arbitrary shortcut metadata in extras and retrieve the
Makoto Onukife9c9662016-07-25 15:12:23 -07001296 * metadata later using {@link ShortcutInfo#getExtras()}.
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001297 */
1298 @NonNull
1299 public Builder setExtras(@NonNull PersistableBundle extras) {
1300 mExtras = extras;
1301 return this;
1302 }
1303
Hakan Seyalioglu58fc95d2016-12-13 15:23:22 -08001304 /**
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001305 * Creates a {@link ShortcutInfo} instance.
1306 */
1307 @NonNull
1308 public ShortcutInfo build() {
1309 return new ShortcutInfo(this);
1310 }
1311 }
1312
1313 /**
Makoto Onuki4a910962016-07-07 13:57:34 -07001314 * Returns the ID of a shortcut.
1315 *
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001316 * <p>Shortcut IDs are unique within each publisher app and must be stable across
Makoto Onukife9c9662016-07-25 15:12:23 -07001317 * devices so that shortcuts will still be valid when restored on a different device.
1318 * See {@link ShortcutManager} for details.
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001319 */
1320 @NonNull
1321 public String getId() {
1322 return mId;
1323 }
1324
1325 /**
Felipe Leme90205ef2019-03-05 09:59:52 -08001326 * Gets the {@link LocusId} associated with this shortcut.
1327 *
1328 * <p>Used by the device's intelligence services to correlate objects (such as
1329 * {@link Notification} and {@link ContentCaptureContext}) that are correlated.
1330 */
1331 @Nullable
1332 public LocusId getLocusId() {
1333 return mLocusId;
1334 }
1335
1336 /**
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001337 * Return the package name of the publisher app.
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001338 */
1339 @NonNull
Makoto Onuki22fcc682016-05-17 14:52:19 -07001340 public String getPackage() {
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001341 return mPackageName;
1342 }
1343
1344 /**
Makoto Onuki4a910962016-07-07 13:57:34 -07001345 * Return the target activity.
Makoto Onuki4d36b3a2016-04-27 12:00:17 -07001346 *
Makoto Onukife9c9662016-07-25 15:12:23 -07001347 * <p>This has nothing to do with the activity that this shortcut will launch.
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001348 * Launcher apps should show the launcher icon for the returned activity alongside
Makoto Onukife9c9662016-07-25 15:12:23 -07001349 * this shortcut.
Makoto Onuki4d36b3a2016-04-27 12:00:17 -07001350 *
Makoto Onuki22fcc682016-05-17 14:52:19 -07001351 * @see Builder#setActivity
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001352 */
1353 @Nullable
Makoto Onuki22fcc682016-05-17 14:52:19 -07001354 public ComponentName getActivity() {
1355 return mActivity;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001356 }
1357
Makoto Onukib08790c2016-06-23 14:05:46 -07001358 /** @hide */
1359 public void setActivity(ComponentName activity) {
1360 mActivity = activity;
1361 }
1362
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001363 /**
Makoto Onuki4a910962016-07-07 13:57:34 -07001364 * Returns the shortcut icon.
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001365 *
1366 * @hide
1367 */
1368 @Nullable
Mathew Inwood8c854f82018-09-14 12:35:36 +01001369 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001370 public Icon getIcon() {
1371 return mIcon;
1372 }
1373
Makoto Onukieddbfec2016-05-31 17:04:34 -07001374 /** @hide -- old signature, the internal code still uses it. */
Makoto Onuki55046222016-03-08 10:49:47 -08001375 @Nullable
Makoto Onukib5a012f2016-06-21 11:13:53 -07001376 @Deprecated
Makoto Onuki22fcc682016-05-17 14:52:19 -07001377 public CharSequence getTitle() {
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001378 return mTitle;
1379 }
1380
Makoto Onukieddbfec2016-05-31 17:04:34 -07001381 /** @hide -- old signature, the internal code still uses it. */
Makoto Onukib5a012f2016-06-21 11:13:53 -07001382 @Deprecated
Makoto Onuki20c95f82016-05-11 16:51:01 -07001383 public int getTitleResId() {
1384 return mTitleResId;
1385 }
1386
Makoto Onukieddbfec2016-05-31 17:04:34 -07001387 /** @hide -- old signature, the internal code still uses it. */
1388 @Nullable
Makoto Onukib5a012f2016-06-21 11:13:53 -07001389 @Deprecated
Makoto Onukieddbfec2016-05-31 17:04:34 -07001390 public CharSequence getText() {
1391 return mText;
1392 }
1393
1394 /** @hide -- old signature, the internal code still uses it. */
Makoto Onukib5a012f2016-06-21 11:13:53 -07001395 @Deprecated
Makoto Onukieddbfec2016-05-31 17:04:34 -07001396 public int getTextResId() {
1397 return mTextResId;
1398 }
1399
1400 /**
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001401 * Return the short description of a shortcut.
Makoto Onukieddbfec2016-05-31 17:04:34 -07001402 *
Makoto Onuki4a910962016-07-07 13:57:34 -07001403 * @see Builder#setShortLabel(CharSequence)
Makoto Onukieddbfec2016-05-31 17:04:34 -07001404 */
1405 @Nullable
1406 public CharSequence getShortLabel() {
1407 return mTitle;
1408 }
1409
Makoto Onuki598aca42016-07-06 16:05:03 -07001410 /** @hide */
Makoto Onukieddbfec2016-05-31 17:04:34 -07001411 public int getShortLabelResourceId() {
1412 return mTitleResId;
1413 }
1414
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001415 /**
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001416 * Return the long description of a shortcut.
Makoto Onuki4a910962016-07-07 13:57:34 -07001417 *
1418 * @see Builder#setLongLabel(CharSequence)
Makoto Onukie3ae7ec2016-03-29 15:45:25 -07001419 */
1420 @Nullable
Makoto Onukieddbfec2016-05-31 17:04:34 -07001421 public CharSequence getLongLabel() {
Makoto Onukie3ae7ec2016-03-29 15:45:25 -07001422 return mText;
1423 }
1424
Makoto Onuki598aca42016-07-06 16:05:03 -07001425 /** @hide */
Makoto Onukieddbfec2016-05-31 17:04:34 -07001426 public int getLongLabelResourceId() {
Makoto Onuki20c95f82016-05-11 16:51:01 -07001427 return mTextResId;
1428 }
1429
1430 /**
Makoto Onukife9c9662016-07-25 15:12:23 -07001431 * Return the message that should be shown when the user attempts to start a shortcut
1432 * that is disabled.
Makoto Onuki4a910962016-07-07 13:57:34 -07001433 *
1434 * @see Builder#setDisabledMessage(CharSequence)
Makoto Onuki20c95f82016-05-11 16:51:01 -07001435 */
1436 @Nullable
Makoto Onuki22fcc682016-05-17 14:52:19 -07001437 public CharSequence getDisabledMessage() {
Makoto Onuki20c95f82016-05-11 16:51:01 -07001438 return mDisabledMessage;
1439 }
1440
Makoto Onuki598aca42016-07-06 16:05:03 -07001441 /** @hide */
Makoto Onukieddbfec2016-05-31 17:04:34 -07001442 public int getDisabledMessageResourceId() {
Makoto Onuki20c95f82016-05-11 16:51:01 -07001443 return mDisabledMessageResId;
1444 }
1445
Makoto Onukia4f89b12017-10-05 10:37:55 -07001446 /** @hide */
1447 public void setDisabledReason(@DisabledReason int reason) {
1448 mDisabledReason = reason;
1449 }
1450
1451 /**
1452 * Returns why a shortcut has been disabled.
1453 */
1454 @DisabledReason
1455 public int getDisabledReason() {
1456 return mDisabledReason;
1457 }
1458
Makoto Onukie3ae7ec2016-03-29 15:45:25 -07001459 /**
Makoto Onukife9c9662016-07-25 15:12:23 -07001460 * Return the shortcut's categories.
Makoto Onuki4a910962016-07-07 13:57:34 -07001461 *
1462 * @see Builder#setCategories(Set)
Makoto Onukib6d35232016-04-04 15:57:17 -07001463 */
1464 @Nullable
Makoto Onukibe73a802016-04-15 14:46:35 -07001465 public Set<String> getCategories() {
Makoto Onukib6d35232016-04-04 15:57:17 -07001466 return mCategories;
1467 }
1468
1469 /**
Makoto Onukife9c9662016-07-25 15:12:23 -07001470 * Returns the intent that is executed when the user selects this shortcut.
1471 * If setIntents() was used, then return the last intent in the array.
Makoto Onuki55046222016-03-08 10:49:47 -08001472 *
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001473 * <p>Launcher apps <b>cannot</b> see the intent. If a {@link ShortcutInfo} is
Makoto Onuki4a910962016-07-07 13:57:34 -07001474 * obtained via {@link LauncherApps}, then this method will always return null.
1475 * Launchers can only start a shortcut intent with {@link LauncherApps#startShortcut}.
Makoto Onuki4d36b3a2016-04-27 12:00:17 -07001476 *
Makoto Onuki4a910962016-07-07 13:57:34 -07001477 * @see Builder#setIntent(Intent)
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001478 */
Makoto Onuki55046222016-03-08 10:49:47 -08001479 @Nullable
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001480 public Intent getIntent() {
Makoto Onuki440a1ea2016-07-20 14:21:18 -07001481 if (mIntents == null || mIntents.length == 0) {
Makoto Onuki55046222016-03-08 10:49:47 -08001482 return null;
1483 }
Makoto Onuki440a1ea2016-07-20 14:21:18 -07001484 final int last = mIntents.length - 1;
1485 final Intent intent = new Intent(mIntents[last]);
1486 return setIntentExtras(intent, mIntentPersistableExtrases[last]);
Makoto Onuki55046222016-03-08 10:49:47 -08001487 }
1488
1489 /**
Makoto Onuki347a6bd2016-07-19 11:13:08 -07001490 * Return the intent set with {@link Builder#setIntents(Intent[])}.
1491 *
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001492 * <p>Launcher apps <b>cannot</b> see the intents. If a {@link ShortcutInfo} is
Makoto Onuki347a6bd2016-07-19 11:13:08 -07001493 * obtained via {@link LauncherApps}, then this method will always return null.
1494 * Launchers can only start a shortcut intent with {@link LauncherApps#startShortcut}.
1495 *
1496 * @see Builder#setIntents(Intent[])
1497 */
1498 @Nullable
Makoto Onuki440a1ea2016-07-20 14:21:18 -07001499 public Intent[] getIntents() {
1500 final Intent[] ret = new Intent[mIntents.length];
1501
1502 for (int i = 0; i < ret.length; i++) {
1503 ret[i] = new Intent(mIntents[i]);
1504 setIntentExtras(ret[i], mIntentPersistableExtrases[i]);
1505 }
1506
1507 return ret;
Makoto Onuki347a6bd2016-07-19 11:13:08 -07001508 }
1509
1510 /**
Makoto Onuki440a1ea2016-07-20 14:21:18 -07001511 * Return "raw" intents, which is the original intents without the extras.
Makoto Onuki55046222016-03-08 10:49:47 -08001512 * @hide
1513 */
1514 @Nullable
Makoto Onuki440a1ea2016-07-20 14:21:18 -07001515 public Intent[] getIntentsNoExtras() {
1516 return mIntents;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001517 }
1518
Makoto Onuki55046222016-03-08 10:49:47 -08001519 /**
Mehdi Alizadeh14242af2018-12-20 20:11:35 -08001520 * Return the Persons set with {@link Builder#setPersons(Person[])}.
1521 *
1522 * @hide
1523 */
1524 @Nullable
Mehdi Alizadeh88873652019-02-04 14:16:46 -08001525 @SystemApi
Mehdi Alizadeh14242af2018-12-20 20:11:35 -08001526 public Person[] getPersons() {
1527 return clonePersons(mPersons);
1528 }
1529
1530 /**
Makoto Onuki440a1ea2016-07-20 14:21:18 -07001531 * The extras in the intents. We convert extras into {@link PersistableBundle} so we can
Makoto Onuki55046222016-03-08 10:49:47 -08001532 * persist them.
1533 * @hide
1534 */
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001535 @Nullable
Makoto Onuki440a1ea2016-07-20 14:21:18 -07001536 public PersistableBundle[] getIntentPersistableExtrases() {
1537 return mIntentPersistableExtrases;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001538 }
1539
Hakan Seyalioglu58fc95d2016-12-13 15:23:22 -08001540 /**
Makoto Onuki9e1f5592016-06-08 12:30:23 -07001541 * "Rank" of a shortcut, which is a non-negative, sequential value that's unique for each
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001542 * {@link #getActivity} for each of the two types of shortcuts (static and dynamic).
Makoto Onuki9e1f5592016-06-08 12:30:23 -07001543 *
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001544 * <p>Because static shortcuts and dynamic shortcuts have overlapping ranks,
1545 * when a launcher app shows shortcuts for an activity, it should first show
1546 * the static shortcuts, followed by the dynamic shortcuts. Within each of those categories,
Makoto Onuki9e1f5592016-06-08 12:30:23 -07001547 * shortcuts should be sorted by rank in ascending order.
1548 *
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001549 * <p><em>Floating shortcuts</em>, or shortcuts that are neither static nor dynamic, will all
1550 * have rank 0, because they aren't sorted.
Makoto Onuki4a910962016-07-07 13:57:34 -07001551 *
1552 * See the {@link ShortcutManager}'s class javadoc for details.
1553 *
1554 * @see Builder#setRank(int)
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001555 */
Makoto Onuki20c95f82016-05-11 16:51:01 -07001556 public int getRank() {
1557 return mRank;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001558 }
1559
Makoto Onuki9e1f5592016-06-08 12:30:23 -07001560 /** @hide */
1561 public boolean hasRank() {
1562 return mRank != RANK_NOT_SET;
1563 }
1564
1565 /** @hide */
1566 public void setRank(int rank) {
1567 mRank = rank;
1568 }
1569
1570 /** @hide */
1571 public void clearImplicitRankAndRankChangedFlag() {
1572 mImplicitRank = 0;
1573 }
1574
1575 /** @hide */
1576 public void setImplicitRank(int rank) {
1577 // Make sure to keep RANK_CHANGED_BIT.
1578 mImplicitRank = (mImplicitRank & RANK_CHANGED_BIT) | (rank & IMPLICIT_RANK_MASK);
1579 }
1580
1581 /** @hide */
1582 public int getImplicitRank() {
1583 return mImplicitRank & IMPLICIT_RANK_MASK;
1584 }
1585
1586 /** @hide */
1587 public void setRankChanged() {
1588 mImplicitRank |= RANK_CHANGED_BIT;
1589 }
1590
1591 /** @hide */
1592 public boolean isRankChanged() {
1593 return (mImplicitRank & RANK_CHANGED_BIT) != 0;
1594 }
1595
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001596 /**
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001597 * Extras that the app can set for any purpose.
Makoto Onuki4a910962016-07-07 13:57:34 -07001598 *
1599 * @see Builder#setExtras(PersistableBundle)
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001600 */
1601 @Nullable
1602 public PersistableBundle getExtras() {
1603 return mExtras;
1604 }
1605
Makoto Onukiabe84422016-04-07 09:41:19 -07001606 /** @hide */
1607 public int getUserId() {
1608 return mUserId;
1609 }
1610
1611 /**
Makoto Onukife9c9662016-07-25 15:12:23 -07001612 * {@link UserHandle} on which the publisher created this shortcut.
Makoto Onukiabe84422016-04-07 09:41:19 -07001613 */
1614 public UserHandle getUserHandle() {
1615 return UserHandle.of(mUserId);
1616 }
1617
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001618 /**
1619 * Last time when any of the fields was updated.
1620 */
1621 public long getLastChangedTimestamp() {
1622 return mLastChangedTimestamp;
1623 }
1624
1625 /** @hide */
1626 @ShortcutFlags
1627 public int getFlags() {
1628 return mFlags;
1629 }
1630
1631 /** @hide*/
Makoto Onukide667372016-03-15 14:29:20 -07001632 public void replaceFlags(@ShortcutFlags int flags) {
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001633 mFlags = flags;
1634 }
1635
1636 /** @hide*/
1637 public void addFlags(@ShortcutFlags int flags) {
1638 mFlags |= flags;
1639 }
1640
1641 /** @hide*/
1642 public void clearFlags(@ShortcutFlags int flags) {
1643 mFlags &= ~flags;
1644 }
1645
1646 /** @hide*/
1647 public boolean hasFlags(@ShortcutFlags int flags) {
1648 return (mFlags & flags) == flags;
1649 }
1650
Makoto Onukibf563b62017-05-04 10:25:30 -07001651 /** @hide */
1652 public boolean isReturnedByServer() {
1653 return hasFlags(FLAG_RETURNED_BY_SERVICE);
1654 }
1655
1656 /** @hide */
1657 public void setReturnedByServer() {
1658 addFlags(FLAG_RETURNED_BY_SERVICE);
1659 }
1660
Mehdi Alizadeh14242af2018-12-20 20:11:35 -08001661 /** @hide */
1662 public boolean isLongLived() {
1663 return hasFlags(FLAG_LONG_LIVED);
1664 }
1665
1666 /** @hide */
1667 public void setLongLived() {
1668 addFlags(FLAG_LONG_LIVED);
1669 }
1670
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001671 /** Return whether a shortcut is dynamic. */
1672 public boolean isDynamic() {
1673 return hasFlags(FLAG_DYNAMIC);
1674 }
1675
1676 /** Return whether a shortcut is pinned. */
1677 public boolean isPinned() {
1678 return hasFlags(FLAG_PINNED);
1679 }
1680
1681 /**
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001682 * Return whether a shortcut is static; that is, whether a shortcut is
1683 * published from AndroidManifest.xml. If {@code true}, the shortcut is
1684 * also {@link #isImmutable()}.
Makoto Onuki22fcc682016-05-17 14:52:19 -07001685 *
1686 * <p>When an app is upgraded and a shortcut is no longer published from AndroidManifest.xml,
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001687 * this will be set to {@code false}. If the shortcut is not pinned, then it'll disappear.
1688 * However, if it's pinned, it will still be visible, {@link #isEnabled()} will be
Makoto Onuki22fcc682016-05-17 14:52:19 -07001689 * {@code false} and {@link #isImmutable()} will be {@code true}.
Makoto Onuki20c95f82016-05-11 16:51:01 -07001690 */
Makoto Onukib5a012f2016-06-21 11:13:53 -07001691 public boolean isDeclaredInManifest() {
Makoto Onuki22fcc682016-05-17 14:52:19 -07001692 return hasFlags(FLAG_MANIFEST);
Makoto Onuki20c95f82016-05-11 16:51:01 -07001693 }
1694
Makoto Onukib5a012f2016-06-21 11:13:53 -07001695 /** @hide kept for unit tests */
1696 @Deprecated
1697 public boolean isManifestShortcut() {
1698 return isDeclaredInManifest();
1699 }
1700
Makoto Onuki22fcc682016-05-17 14:52:19 -07001701 /**
Makoto Onuki9fd90192017-01-06 18:31:03 +00001702 * @return true if pinned but neither static nor dynamic.
Makoto Onuki22fcc682016-05-17 14:52:19 -07001703 * @hide
1704 */
1705 public boolean isFloating() {
1706 return isPinned() && !(isDynamic() || isManifestShortcut());
1707 }
1708
1709 /** @hide */
1710 public boolean isOriginallyFromManifest() {
1711 return hasFlags(FLAG_IMMUTABLE);
1712 }
1713
Makoto Onukia4f89b12017-10-05 10:37:55 -07001714 /** @hide */
1715 public boolean isDynamicVisible() {
1716 return isDynamic() && isVisibleToPublisher();
1717 }
1718
1719 /** @hide */
1720 public boolean isPinnedVisible() {
1721 return isPinned() && isVisibleToPublisher();
1722 }
1723
1724 /** @hide */
1725 public boolean isManifestVisible() {
1726 return isDeclaredInManifest() && isVisibleToPublisher();
1727 }
1728
Makoto Onuki22fcc682016-05-17 14:52:19 -07001729 /**
1730 * Return if a shortcut is immutable, in which case it cannot be modified with any of
1731 * {@link ShortcutManager} APIs.
1732 *
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001733 * <p>All static shortcuts are immutable. When a static shortcut is pinned and is then
1734 * disabled because it doesn't appear in AndroidManifest.xml for a newer version of the
1735 * app, {@link #isDeclaredInManifest()} returns {@code false}, but the shortcut
1736 * is still immutable.
Makoto Onuki22fcc682016-05-17 14:52:19 -07001737 *
1738 * <p>All shortcuts originally published via the {@link ShortcutManager} APIs
1739 * are all mutable.
1740 */
1741 public boolean isImmutable() {
1742 return hasFlags(FLAG_IMMUTABLE);
1743 }
1744
1745 /**
1746 * Returns {@code false} if a shortcut is disabled with
1747 * {@link ShortcutManager#disableShortcuts}.
1748 */
1749 public boolean isEnabled() {
Makoto Onuki20c95f82016-05-11 16:51:01 -07001750 return !hasFlags(FLAG_DISABLED);
1751 }
1752
Makoto Onuki22fcc682016-05-17 14:52:19 -07001753 /** @hide */
1754 public boolean isAlive() {
1755 return hasFlags(FLAG_PINNED) || hasFlags(FLAG_DYNAMIC) || hasFlags(FLAG_MANIFEST);
1756 }
1757
1758 /** @hide */
1759 public boolean usesQuota() {
1760 return hasFlags(FLAG_DYNAMIC) || hasFlags(FLAG_MANIFEST);
1761 }
1762
Makoto Onuki20c95f82016-05-11 16:51:01 -07001763 /**
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001764 * Return whether a shortcut's icon is a resource in the owning package.
1765 *
Makoto Onukib5a012f2016-06-21 11:13:53 -07001766 * @hide internal/unit tests only
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001767 */
1768 public boolean hasIconResource() {
1769 return hasFlags(FLAG_HAS_ICON_RES);
1770 }
1771
Makoto Onuki20c95f82016-05-11 16:51:01 -07001772 /** @hide */
1773 public boolean hasStringResources() {
1774 return (mTitleResId != 0) || (mTextResId != 0) || (mDisabledMessageResId != 0);
1775 }
1776
1777 /** @hide */
1778 public boolean hasAnyResources() {
1779 return hasIconResource() || hasStringResources();
1780 }
1781
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001782 /**
1783 * Return whether a shortcut's icon is stored as a file.
1784 *
Makoto Onukib5a012f2016-06-21 11:13:53 -07001785 * @hide internal/unit tests only
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001786 */
1787 public boolean hasIconFile() {
1788 return hasFlags(FLAG_HAS_ICON_FILE);
1789 }
1790
Makoto Onuki55046222016-03-08 10:49:47 -08001791 /**
Hyunyoung Songe4179e22017-03-01 12:51:26 -08001792 * Return whether a shortcut's icon is adaptive bitmap following design guideline
Makoto Onukibf563b62017-05-04 10:25:30 -07001793 * defined in {@link android.graphics.drawable.AdaptiveIconDrawable}.
Hyunyoung Songf281e7a2017-02-13 10:57:42 -08001794 *
1795 * @hide internal/unit tests only
1796 */
Hyunyoung Songe4179e22017-03-01 12:51:26 -08001797 public boolean hasAdaptiveBitmap() {
1798 return hasFlags(FLAG_ADAPTIVE_BITMAP);
Hyunyoung Songf281e7a2017-02-13 10:57:42 -08001799 }
1800
Makoto Onuki475c3652017-05-08 14:29:03 -07001801 /** @hide */
1802 public boolean isIconPendingSave() {
1803 return hasFlags(FLAG_ICON_FILE_PENDING_SAVE);
1804 }
1805
1806 /** @hide */
1807 public void setIconPendingSave() {
1808 addFlags(FLAG_ICON_FILE_PENDING_SAVE);
1809 }
1810
1811 /** @hide */
1812 public void clearIconPendingSave() {
1813 clearFlags(FLAG_ICON_FILE_PENDING_SAVE);
1814 }
1815
Hyunyoung Songf281e7a2017-02-13 10:57:42 -08001816 /**
Makoto Onukia4f89b12017-10-05 10:37:55 -07001817 * When the system wasn't able to restore a shortcut, it'll still be registered to the system
1818 * but disabled, and such shortcuts will not be visible to the publisher. They're still visible
1819 * to launchers though.
1820 *
1821 * @hide
1822 */
1823 @TestApi
1824 public boolean isVisibleToPublisher() {
1825 return !isDisabledForRestoreIssue(mDisabledReason);
1826 }
1827
1828 /**
Makoto Onuki55046222016-03-08 10:49:47 -08001829 * Return whether a shortcut only contains "key" information only or not. If true, only the
1830 * following fields are available.
1831 * <ul>
1832 * <li>{@link #getId()}
Makoto Onuki22fcc682016-05-17 14:52:19 -07001833 * <li>{@link #getPackage()}
Makoto Onuki4d6b87f2016-06-17 13:47:40 -07001834 * <li>{@link #getActivity()}
Makoto Onuki55046222016-03-08 10:49:47 -08001835 * <li>{@link #getLastChangedTimestamp()}
1836 * <li>{@link #isDynamic()}
1837 * <li>{@link #isPinned()}
Makoto Onukib5a012f2016-06-21 11:13:53 -07001838 * <li>{@link #isDeclaredInManifest()}
1839 * <li>{@link #isImmutable()}
1840 * <li>{@link #isEnabled()}
1841 * <li>{@link #getUserHandle()}
Makoto Onuki55046222016-03-08 10:49:47 -08001842 * </ul>
Makoto Onuki4a910962016-07-07 13:57:34 -07001843 *
Makoto Onukife9c9662016-07-25 15:12:23 -07001844 * <p>For performance reasons, shortcuts passed to
1845 * {@link LauncherApps.Callback#onShortcutsChanged(String, List, UserHandle)} as well as those
1846 * returned from {@link LauncherApps#getShortcuts(ShortcutQuery, UserHandle)}
1847 * while using the {@link ShortcutQuery#FLAG_GET_KEY_FIELDS_ONLY} option contain only key
1848 * information.
Makoto Onuki55046222016-03-08 10:49:47 -08001849 */
1850 public boolean hasKeyFieldsOnly() {
1851 return hasFlags(FLAG_KEY_FIELDS_ONLY);
1852 }
1853
Makoto Onukib5a012f2016-06-21 11:13:53 -07001854 /** @hide */
Makoto Onuki20c95f82016-05-11 16:51:01 -07001855 public boolean hasStringResourcesResolved() {
1856 return hasFlags(FLAG_STRINGS_RESOLVED);
1857 }
1858
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001859 /** @hide */
1860 public void updateTimestamp() {
1861 mLastChangedTimestamp = System.currentTimeMillis();
1862 }
1863
1864 /** @hide */
1865 // VisibleForTesting
1866 public void setTimestamp(long value) {
1867 mLastChangedTimestamp = value;
1868 }
1869
1870 /** @hide */
Makoto Onuki55046222016-03-08 10:49:47 -08001871 public void clearIcon() {
1872 mIcon = null;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001873 }
1874
1875 /** @hide */
Makoto Onuki55046222016-03-08 10:49:47 -08001876 public void setIconResourceId(int iconResourceId) {
Makoto Onuki157b1622016-06-02 16:13:10 -07001877 if (mIconResId != iconResourceId) {
1878 mIconResName = null;
1879 }
1880 mIconResId = iconResourceId;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001881 }
1882
Makoto Onukib6d35232016-04-04 15:57:17 -07001883 /**
1884 * Get the resource ID for the icon, valid only when {@link #hasIconResource()} } is true.
Makoto Onukib5a012f2016-06-21 11:13:53 -07001885 * @hide internal / tests only.
Makoto Onukib6d35232016-04-04 15:57:17 -07001886 */
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001887 public int getIconResourceId() {
Makoto Onuki157b1622016-06-02 16:13:10 -07001888 return mIconResId;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001889 }
1890
Makoto Onuki475c3652017-05-08 14:29:03 -07001891 /**
1892 * Bitmap path. Note this will be null even if {@link #hasIconFile()} is set when the save
1893 * is pending. Use {@link #isIconPendingSave()} to check it.
1894 *
1895 * @hide
1896 */
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001897 public String getBitmapPath() {
1898 return mBitmapPath;
1899 }
1900
1901 /** @hide */
1902 public void setBitmapPath(String bitmapPath) {
1903 mBitmapPath = bitmapPath;
1904 }
1905
Makoto Onuki22fcc682016-05-17 14:52:19 -07001906 /** @hide */
1907 public void setDisabledMessageResId(int disabledMessageResId) {
Makoto Onuki157b1622016-06-02 16:13:10 -07001908 if (mDisabledMessageResId != disabledMessageResId) {
1909 mDisabledMessageResName = null;
1910 }
Makoto Onuki22fcc682016-05-17 14:52:19 -07001911 mDisabledMessageResId = disabledMessageResId;
1912 mDisabledMessage = null;
1913 }
1914
1915 /** @hide */
1916 public void setDisabledMessage(String disabledMessage) {
1917 mDisabledMessage = disabledMessage;
1918 mDisabledMessageResId = 0;
Makoto Onuki157b1622016-06-02 16:13:10 -07001919 mDisabledMessageResName = null;
1920 }
1921
1922 /** @hide */
1923 public String getTitleResName() {
1924 return mTitleResName;
1925 }
1926
1927 /** @hide */
1928 public void setTitleResName(String titleResName) {
1929 mTitleResName = titleResName;
1930 }
1931
1932 /** @hide */
1933 public String getTextResName() {
1934 return mTextResName;
1935 }
1936
1937 /** @hide */
1938 public void setTextResName(String textResName) {
1939 mTextResName = textResName;
1940 }
1941
1942 /** @hide */
1943 public String getDisabledMessageResName() {
1944 return mDisabledMessageResName;
1945 }
1946
1947 /** @hide */
1948 public void setDisabledMessageResName(String disabledMessageResName) {
1949 mDisabledMessageResName = disabledMessageResName;
1950 }
1951
1952 /** @hide */
1953 public String getIconResName() {
1954 return mIconResName;
1955 }
1956
1957 /** @hide */
1958 public void setIconResName(String iconResName) {
1959 mIconResName = iconResName;
Makoto Onuki22fcc682016-05-17 14:52:19 -07001960 }
1961
Makoto Onukidf6da042016-06-16 09:51:40 -07001962 /**
Kevin Hufnagle68d699d2016-10-14 19:04:51 -07001963 * Replaces the intent.
Makoto Onukidf6da042016-06-16 09:51:40 -07001964 *
1965 * @throws IllegalArgumentException when extra is not compatible with {@link PersistableBundle}.
1966 *
1967 * @hide
1968 */
Makoto Onuki440a1ea2016-07-20 14:21:18 -07001969 public void setIntents(Intent[] intents) throws IllegalArgumentException {
1970 Preconditions.checkNotNull(intents);
1971 Preconditions.checkArgument(intents.length > 0);
Makoto Onukidf6da042016-06-16 09:51:40 -07001972
Makoto Onuki440a1ea2016-07-20 14:21:18 -07001973 mIntents = cloneIntents(intents);
1974 fixUpIntentExtras();
1975 }
Makoto Onukidf6da042016-06-16 09:51:40 -07001976
Makoto Onuki440a1ea2016-07-20 14:21:18 -07001977 /** @hide */
1978 public static Intent setIntentExtras(Intent intent, PersistableBundle extras) {
1979 if (extras == null) {
Makoto Onukidf6da042016-06-16 09:51:40 -07001980 intent.replaceExtras((Bundle) null);
Makoto Onukidf6da042016-06-16 09:51:40 -07001981 } else {
Makoto Onuki440a1ea2016-07-20 14:21:18 -07001982 intent.replaceExtras(new Bundle(extras));
Makoto Onukidf6da042016-06-16 09:51:40 -07001983 }
Makoto Onuki440a1ea2016-07-20 14:21:18 -07001984 return intent;
Makoto Onukidf6da042016-06-16 09:51:40 -07001985 }
1986
1987 /**
1988 * Replaces the categories.
1989 *
1990 * @hide
1991 */
1992 public void setCategories(Set<String> categories) {
1993 mCategories = cloneCategories(categories);
1994 }
1995
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001996 private ShortcutInfo(Parcel source) {
1997 final ClassLoader cl = getClass().getClassLoader();
1998
Makoto Onukiabe84422016-04-07 09:41:19 -07001999 mUserId = source.readInt();
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002000 mId = source.readString();
2001 mPackageName = source.readString();
Makoto Onuki22fcc682016-05-17 14:52:19 -07002002 mActivity = source.readParcelable(cl);
Makoto Onuki4d6b87f2016-06-17 13:47:40 -07002003 mFlags = source.readInt();
2004 mIconResId = source.readInt();
2005 mLastChangedTimestamp = source.readLong();
Makoto Onukia4f89b12017-10-05 10:37:55 -07002006 mDisabledReason = source.readInt();
Makoto Onuki4d6b87f2016-06-17 13:47:40 -07002007
2008 if (source.readInt() == 0) {
2009 return; // key information only.
2010 }
2011
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002012 mIcon = source.readParcelable(cl);
Makoto Onuki22fcc682016-05-17 14:52:19 -07002013 mTitle = source.readCharSequence();
Makoto Onuki20c95f82016-05-11 16:51:01 -07002014 mTitleResId = source.readInt();
Makoto Onuki22fcc682016-05-17 14:52:19 -07002015 mText = source.readCharSequence();
Makoto Onuki20c95f82016-05-11 16:51:01 -07002016 mTextResId = source.readInt();
Makoto Onuki22fcc682016-05-17 14:52:19 -07002017 mDisabledMessage = source.readCharSequence();
Makoto Onuki20c95f82016-05-11 16:51:01 -07002018 mDisabledMessageResId = source.readInt();
Makoto Onuki440a1ea2016-07-20 14:21:18 -07002019 mIntents = source.readParcelableArray(cl, Intent.class);
2020 mIntentPersistableExtrases = source.readParcelableArray(cl, PersistableBundle.class);
Makoto Onuki20c95f82016-05-11 16:51:01 -07002021 mRank = source.readInt();
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002022 mExtras = source.readParcelable(cl);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002023 mBitmapPath = source.readString();
Makoto Onukibe73a802016-04-15 14:46:35 -07002024
Makoto Onuki157b1622016-06-02 16:13:10 -07002025 mIconResName = source.readString();
2026 mTitleResName = source.readString();
2027 mTextResName = source.readString();
2028 mDisabledMessageResName = source.readString();
2029
Makoto Onukibe73a802016-04-15 14:46:35 -07002030 int N = source.readInt();
2031 if (N == 0) {
2032 mCategories = null;
2033 } else {
2034 mCategories = new ArraySet<>(N);
2035 for (int i = 0; i < N; i++) {
2036 mCategories.add(source.readString().intern());
2037 }
2038 }
Mehdi Alizadeh14242af2018-12-20 20:11:35 -08002039
2040 mPersons = source.readParcelableArray(cl, Person.class);
Felipe Leme90205ef2019-03-05 09:59:52 -08002041 mLocusId = source.readParcelable(cl);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002042 }
2043
2044 @Override
2045 public void writeToParcel(Parcel dest, int flags) {
Makoto Onukiabe84422016-04-07 09:41:19 -07002046 dest.writeInt(mUserId);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002047 dest.writeString(mId);
2048 dest.writeString(mPackageName);
Makoto Onuki22fcc682016-05-17 14:52:19 -07002049 dest.writeParcelable(mActivity, flags);
Makoto Onuki4d6b87f2016-06-17 13:47:40 -07002050 dest.writeInt(mFlags);
2051 dest.writeInt(mIconResId);
2052 dest.writeLong(mLastChangedTimestamp);
Makoto Onukia4f89b12017-10-05 10:37:55 -07002053 dest.writeInt(mDisabledReason);
Makoto Onuki4d6b87f2016-06-17 13:47:40 -07002054
2055 if (hasKeyFieldsOnly()) {
2056 dest.writeInt(0);
2057 return;
2058 }
2059 dest.writeInt(1);
2060
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002061 dest.writeParcelable(mIcon, flags);
Makoto Onuki22fcc682016-05-17 14:52:19 -07002062 dest.writeCharSequence(mTitle);
Makoto Onuki20c95f82016-05-11 16:51:01 -07002063 dest.writeInt(mTitleResId);
Makoto Onuki22fcc682016-05-17 14:52:19 -07002064 dest.writeCharSequence(mText);
Makoto Onuki20c95f82016-05-11 16:51:01 -07002065 dest.writeInt(mTextResId);
Makoto Onuki22fcc682016-05-17 14:52:19 -07002066 dest.writeCharSequence(mDisabledMessage);
Makoto Onuki20c95f82016-05-11 16:51:01 -07002067 dest.writeInt(mDisabledMessageResId);
Makoto Onukibe73a802016-04-15 14:46:35 -07002068
Makoto Onuki440a1ea2016-07-20 14:21:18 -07002069 dest.writeParcelableArray(mIntents, flags);
2070 dest.writeParcelableArray(mIntentPersistableExtrases, flags);
Makoto Onuki20c95f82016-05-11 16:51:01 -07002071 dest.writeInt(mRank);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002072 dest.writeParcelable(mExtras, flags);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002073 dest.writeString(mBitmapPath);
Makoto Onukibe73a802016-04-15 14:46:35 -07002074
Makoto Onuki157b1622016-06-02 16:13:10 -07002075 dest.writeString(mIconResName);
2076 dest.writeString(mTitleResName);
2077 dest.writeString(mTextResName);
2078 dest.writeString(mDisabledMessageResName);
2079
Makoto Onukibe73a802016-04-15 14:46:35 -07002080 if (mCategories != null) {
2081 final int N = mCategories.size();
2082 dest.writeInt(N);
2083 for (int i = 0; i < N; i++) {
2084 dest.writeString(mCategories.valueAt(i));
2085 }
2086 } else {
2087 dest.writeInt(0);
2088 }
Mehdi Alizadeh14242af2018-12-20 20:11:35 -08002089
2090 dest.writeParcelableArray(mPersons, flags);
Felipe Leme90205ef2019-03-05 09:59:52 -08002091 dest.writeParcelable(mLocusId, flags);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002092 }
2093
Jeff Sharkey9e8f83d2019-02-28 12:06:45 -07002094 public static final @android.annotation.NonNull Creator<ShortcutInfo> CREATOR =
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002095 new Creator<ShortcutInfo>() {
2096 public ShortcutInfo createFromParcel(Parcel source) {
2097 return new ShortcutInfo(source);
2098 }
2099 public ShortcutInfo[] newArray(int size) {
2100 return new ShortcutInfo[size];
2101 }
2102 };
2103
2104 @Override
2105 public int describeContents() {
2106 return 0;
2107 }
2108
Makoto Onuki6208c672017-10-02 16:20:35 -07002109
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002110 /**
2111 * Return a string representation, intended for logging. Some fields will be retracted.
2112 */
2113 @Override
2114 public String toString() {
Makoto Onuki6208c672017-10-02 16:20:35 -07002115 return toStringInner(/* secure =*/ true, /* includeInternalData =*/ false,
2116 /*indent=*/ null);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002117 }
2118
2119 /** @hide */
2120 public String toInsecureString() {
Makoto Onuki6208c672017-10-02 16:20:35 -07002121 return toStringInner(/* secure =*/ false, /* includeInternalData =*/ true,
2122 /*indent=*/ null);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002123 }
2124
Makoto Onuki6208c672017-10-02 16:20:35 -07002125 /** @hide */
2126 public String toDumpString(String indent) {
2127 return toStringInner(/* secure =*/ false, /* includeInternalData =*/ true, indent);
2128 }
2129
2130 private void addIndentOrComma(StringBuilder sb, String indent) {
2131 if (indent != null) {
2132 sb.append("\n ");
2133 sb.append(indent);
2134 } else {
2135 sb.append(", ");
2136 }
2137 }
2138
2139 private String toStringInner(boolean secure, boolean includeInternalData, String indent) {
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002140 final StringBuilder sb = new StringBuilder();
Makoto Onuki6208c672017-10-02 16:20:35 -07002141
2142 if (indent != null) {
2143 sb.append(indent);
2144 }
2145
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002146 sb.append("ShortcutInfo {");
2147
2148 sb.append("id=");
2149 sb.append(secure ? "***" : mId);
2150
Makoto Onuki22fcc682016-05-17 14:52:19 -07002151 sb.append(", flags=0x");
2152 sb.append(Integer.toHexString(mFlags));
2153 sb.append(" [");
Makoto Onukia4f89b12017-10-05 10:37:55 -07002154 if ((mFlags & FLAG_SHADOW) != 0) {
2155 // Note the shadow flag isn't actually used anywhere and it's just for dumpsys, so
2156 // we don't have an isXxx for this.
2157 sb.append("Sdw");
2158 }
Makoto Onuki22fcc682016-05-17 14:52:19 -07002159 if (!isEnabled()) {
Makoto Onuki6208c672017-10-02 16:20:35 -07002160 sb.append("Dis");
Makoto Onuki22fcc682016-05-17 14:52:19 -07002161 }
2162 if (isImmutable()) {
2163 sb.append("Im");
2164 }
2165 if (isManifestShortcut()) {
Makoto Onuki6208c672017-10-02 16:20:35 -07002166 sb.append("Man");
Makoto Onuki22fcc682016-05-17 14:52:19 -07002167 }
2168 if (isDynamic()) {
Makoto Onuki6208c672017-10-02 16:20:35 -07002169 sb.append("Dyn");
Makoto Onuki22fcc682016-05-17 14:52:19 -07002170 }
2171 if (isPinned()) {
Makoto Onuki6208c672017-10-02 16:20:35 -07002172 sb.append("Pin");
Makoto Onuki22fcc682016-05-17 14:52:19 -07002173 }
2174 if (hasIconFile()) {
Makoto Onuki6208c672017-10-02 16:20:35 -07002175 sb.append("Ic-f");
Makoto Onuki22fcc682016-05-17 14:52:19 -07002176 }
Makoto Onuki475c3652017-05-08 14:29:03 -07002177 if (isIconPendingSave()) {
Makoto Onuki6208c672017-10-02 16:20:35 -07002178 sb.append("Pens");
Makoto Onuki475c3652017-05-08 14:29:03 -07002179 }
Makoto Onuki22fcc682016-05-17 14:52:19 -07002180 if (hasIconResource()) {
Makoto Onuki6208c672017-10-02 16:20:35 -07002181 sb.append("Ic-r");
Makoto Onuki22fcc682016-05-17 14:52:19 -07002182 }
2183 if (hasKeyFieldsOnly()) {
Makoto Onuki6208c672017-10-02 16:20:35 -07002184 sb.append("Key");
Makoto Onuki22fcc682016-05-17 14:52:19 -07002185 }
2186 if (hasStringResourcesResolved()) {
Makoto Onuki6208c672017-10-02 16:20:35 -07002187 sb.append("Str");
Makoto Onuki22fcc682016-05-17 14:52:19 -07002188 }
Makoto Onukibf563b62017-05-04 10:25:30 -07002189 if (isReturnedByServer()) {
Makoto Onuki6208c672017-10-02 16:20:35 -07002190 sb.append("Rets");
Makoto Onukibf563b62017-05-04 10:25:30 -07002191 }
Mehdi Alizadeh14242af2018-12-20 20:11:35 -08002192 if (isLongLived()) {
2193 sb.append("Liv");
2194 }
Makoto Onuki22fcc682016-05-17 14:52:19 -07002195 sb.append("]");
2196
Makoto Onuki6208c672017-10-02 16:20:35 -07002197 addIndentOrComma(sb, indent);
2198
2199 sb.append("packageName=");
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002200 sb.append(mPackageName);
2201
Makoto Onukia4f89b12017-10-05 10:37:55 -07002202 addIndentOrComma(sb, indent);
2203
2204 sb.append("activity=");
Makoto Onuki22fcc682016-05-17 14:52:19 -07002205 sb.append(mActivity);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002206
Makoto Onuki6208c672017-10-02 16:20:35 -07002207 addIndentOrComma(sb, indent);
2208
2209 sb.append("shortLabel=");
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002210 sb.append(secure ? "***" : mTitle);
Makoto Onukieddbfec2016-05-31 17:04:34 -07002211 sb.append(", resId=");
Makoto Onuki20c95f82016-05-11 16:51:01 -07002212 sb.append(mTitleResId);
Makoto Onuki157b1622016-06-02 16:13:10 -07002213 sb.append("[");
2214 sb.append(mTitleResName);
2215 sb.append("]");
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002216
Makoto Onuki6208c672017-10-02 16:20:35 -07002217 addIndentOrComma(sb, indent);
2218
2219 sb.append("longLabel=");
Makoto Onukie3ae7ec2016-03-29 15:45:25 -07002220 sb.append(secure ? "***" : mText);
Makoto Onukieddbfec2016-05-31 17:04:34 -07002221 sb.append(", resId=");
Makoto Onuki20c95f82016-05-11 16:51:01 -07002222 sb.append(mTextResId);
Makoto Onuki157b1622016-06-02 16:13:10 -07002223 sb.append("[");
2224 sb.append(mTextResName);
2225 sb.append("]");
Makoto Onuki20c95f82016-05-11 16:51:01 -07002226
Makoto Onuki6208c672017-10-02 16:20:35 -07002227 addIndentOrComma(sb, indent);
2228
2229 sb.append("disabledMessage=");
Makoto Onuki20c95f82016-05-11 16:51:01 -07002230 sb.append(secure ? "***" : mDisabledMessage);
Makoto Onukieddbfec2016-05-31 17:04:34 -07002231 sb.append(", resId=");
Makoto Onuki20c95f82016-05-11 16:51:01 -07002232 sb.append(mDisabledMessageResId);
Makoto Onuki157b1622016-06-02 16:13:10 -07002233 sb.append("[");
2234 sb.append(mDisabledMessageResName);
2235 sb.append("]");
Makoto Onukie3ae7ec2016-03-29 15:45:25 -07002236
Makoto Onuki6208c672017-10-02 16:20:35 -07002237 addIndentOrComma(sb, indent);
2238
Makoto Onukia4f89b12017-10-05 10:37:55 -07002239 sb.append("disabledReason=");
Makoto Onukib1588c02017-10-12 15:11:45 -07002240 sb.append(getDisabledReasonDebugString(mDisabledReason));
Makoto Onukia4f89b12017-10-05 10:37:55 -07002241
2242 addIndentOrComma(sb, indent);
2243
Makoto Onuki6208c672017-10-02 16:20:35 -07002244 sb.append("categories=");
Makoto Onukib6d35232016-04-04 15:57:17 -07002245 sb.append(mCategories);
2246
Makoto Onuki6208c672017-10-02 16:20:35 -07002247 addIndentOrComma(sb, indent);
2248
Mehdi Alizadeh14242af2018-12-20 20:11:35 -08002249 sb.append("persons=");
2250 sb.append(mPersons);
2251
2252 addIndentOrComma(sb, indent);
2253
Makoto Onuki6208c672017-10-02 16:20:35 -07002254 sb.append("icon=");
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002255 sb.append(mIcon);
2256
Makoto Onuki6208c672017-10-02 16:20:35 -07002257 addIndentOrComma(sb, indent);
2258
2259 sb.append("rank=");
Makoto Onuki20c95f82016-05-11 16:51:01 -07002260 sb.append(mRank);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002261
2262 sb.append(", timestamp=");
2263 sb.append(mLastChangedTimestamp);
2264
Makoto Onuki6208c672017-10-02 16:20:35 -07002265 addIndentOrComma(sb, indent);
2266
2267 sb.append("intents=");
Makoto Onuki440a1ea2016-07-20 14:21:18 -07002268 if (mIntents == null) {
2269 sb.append("null");
2270 } else {
2271 if (secure) {
2272 sb.append("size:");
2273 sb.append(mIntents.length);
2274 } else {
2275 final int size = mIntents.length;
2276 sb.append("[");
2277 String sep = "";
2278 for (int i = 0; i < size; i++) {
2279 sb.append(sep);
2280 sep = ", ";
2281 sb.append(mIntents[i]);
2282 sb.append("/");
2283 sb.append(mIntentPersistableExtrases[i]);
2284 }
2285 sb.append("]");
2286 }
2287 }
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002288
Makoto Onuki6208c672017-10-02 16:20:35 -07002289 addIndentOrComma(sb, indent);
2290
2291 sb.append("extras=");
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002292 sb.append(mExtras);
2293
2294 if (includeInternalData) {
Makoto Onuki6208c672017-10-02 16:20:35 -07002295 addIndentOrComma(sb, indent);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002296
Makoto Onuki6208c672017-10-02 16:20:35 -07002297 sb.append("iconRes=");
Makoto Onuki157b1622016-06-02 16:13:10 -07002298 sb.append(mIconResId);
2299 sb.append("[");
2300 sb.append(mIconResName);
2301 sb.append("]");
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002302
2303 sb.append(", bitmapPath=");
2304 sb.append(mBitmapPath);
2305 }
2306
Felipe Leme90205ef2019-03-05 09:59:52 -08002307 if (mLocusId != null) {
2308 sb.append("locusId="); sb.append(mLocusId); // LocusId.toString() is PII-safe.
2309 }
2310
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002311 sb.append("}");
2312 return sb.toString();
2313 }
2314
2315 /** @hide */
Makoto Onukiabe84422016-04-07 09:41:19 -07002316 public ShortcutInfo(
Makoto Onuki22fcc682016-05-17 14:52:19 -07002317 @UserIdInt int userId, String id, String packageName, ComponentName activity,
Makoto Onuki157b1622016-06-02 16:13:10 -07002318 Icon icon, CharSequence title, int titleResId, String titleResName,
2319 CharSequence text, int textResId, String textResName,
2320 CharSequence disabledMessage, int disabledMessageResId, String disabledMessageResName,
Makoto Onuki440a1ea2016-07-20 14:21:18 -07002321 Set<String> categories, Intent[] intentsWithExtras, int rank, PersistableBundle extras,
2322 long lastChangedTimestamp,
Mehdi Alizadehebb4b602019-02-05 15:52:18 -08002323 int flags, int iconResId, String iconResName, String bitmapPath, int disabledReason,
Felipe Leme90205ef2019-03-05 09:59:52 -08002324 Person[] persons, LocusId locusId) {
Makoto Onukiabe84422016-04-07 09:41:19 -07002325 mUserId = userId;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002326 mId = id;
2327 mPackageName = packageName;
Makoto Onuki22fcc682016-05-17 14:52:19 -07002328 mActivity = activity;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002329 mIcon = icon;
2330 mTitle = title;
Makoto Onuki20c95f82016-05-11 16:51:01 -07002331 mTitleResId = titleResId;
Makoto Onuki157b1622016-06-02 16:13:10 -07002332 mTitleResName = titleResName;
Makoto Onukie3ae7ec2016-03-29 15:45:25 -07002333 mText = text;
Makoto Onuki20c95f82016-05-11 16:51:01 -07002334 mTextResId = textResId;
Makoto Onuki157b1622016-06-02 16:13:10 -07002335 mTextResName = textResName;
Makoto Onuki20c95f82016-05-11 16:51:01 -07002336 mDisabledMessage = disabledMessage;
2337 mDisabledMessageResId = disabledMessageResId;
Makoto Onuki157b1622016-06-02 16:13:10 -07002338 mDisabledMessageResName = disabledMessageResName;
Makoto Onukidf6da042016-06-16 09:51:40 -07002339 mCategories = cloneCategories(categories);
Makoto Onuki440a1ea2016-07-20 14:21:18 -07002340 mIntents = cloneIntents(intentsWithExtras);
2341 fixUpIntentExtras();
Makoto Onuki20c95f82016-05-11 16:51:01 -07002342 mRank = rank;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002343 mExtras = extras;
2344 mLastChangedTimestamp = lastChangedTimestamp;
2345 mFlags = flags;
Makoto Onuki157b1622016-06-02 16:13:10 -07002346 mIconResId = iconResId;
2347 mIconResName = iconResName;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002348 mBitmapPath = bitmapPath;
Makoto Onukia4f89b12017-10-05 10:37:55 -07002349 mDisabledReason = disabledReason;
Mehdi Alizadehebb4b602019-02-05 15:52:18 -08002350 mPersons = persons;
Felipe Leme90205ef2019-03-05 09:59:52 -08002351 mLocusId = locusId;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08002352 }
2353}