blob: 8223363a2bc819583b92f870020d769e46598ae4 [file] [log] [blame]
Amith Yamasani4f582632014-02-19 14:31:52 -08001/*
2 * Copyright (C) 2014 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 */
16
17package android.content.pm;
18
Makoto Onuki6f7362d92016-03-04 13:39:41 -080019import android.annotation.IntDef;
20import android.annotation.NonNull;
21import android.annotation.Nullable;
Makoto Onuki2d895c32016-12-02 15:48:40 -080022import android.annotation.SdkConstant;
23import android.annotation.SdkConstant.SdkConstantType;
Makoto Onukib1588c02017-10-12 15:11:45 -070024import android.annotation.SystemService;
Makoto Onuki5ba0d3e2016-04-11 14:03:46 -070025import android.annotation.TestApi;
Makoto Onukia37ac3d2017-04-14 12:33:10 -070026import android.app.PendingIntent;
27import android.appwidget.AppWidgetManager;
Sunny Goyal87a563e2017-01-01 19:42:45 -080028import android.appwidget.AppWidgetProviderInfo;
Makoto Onuki83f6d2d2016-07-11 14:30:19 -070029import android.content.ActivityNotFoundException;
Amith Yamasani4f582632014-02-19 14:31:52 -080030import android.content.ComponentName;
31import android.content.Context;
32import android.content.Intent;
Sunny Goyala6be88a2017-01-12 16:27:58 -080033import android.content.IntentSender;
Kenny Guy77242752016-01-15 13:29:06 +000034import android.content.pm.PackageManager.ApplicationInfoFlags;
Makoto Onuki04b9aab2016-05-23 17:13:30 -070035import android.content.pm.PackageManager.NameNotFoundException;
36import android.content.res.Resources;
37import android.graphics.Bitmap;
38import android.graphics.BitmapFactory;
Amith Yamasani4f582632014-02-19 14:31:52 -080039import android.graphics.Rect;
Makoto Onukib1588c02017-10-12 15:11:45 -070040import android.graphics.drawable.AdaptiveIconDrawable;
Makoto Onuki04b9aab2016-05-23 17:13:30 -070041import android.graphics.drawable.BitmapDrawable;
Makoto Onuki20c95f82016-05-11 16:51:01 -070042import android.graphics.drawable.Drawable;
Makoto Onuki2d895c32016-12-02 15:48:40 -080043import android.graphics.drawable.Icon;
Amith Yamasani4f582632014-02-19 14:31:52 -080044import android.os.Bundle;
Kenny Guyb42c89b2014-07-28 19:20:07 +010045import android.os.Handler;
46import android.os.Looper;
47import android.os.Message;
Makoto Onuki2d895c32016-12-02 15:48:40 -080048import android.os.Parcel;
Makoto Onuki6f7362d92016-03-04 13:39:41 -080049import android.os.ParcelFileDescriptor;
Makoto Onuki2d895c32016-12-02 15:48:40 -080050import android.os.Parcelable;
Amith Yamasani4f582632014-02-19 14:31:52 -080051import android.os.RemoteException;
Makoto Onuki5ba0d3e2016-04-11 14:03:46 -070052import android.os.ServiceManager;
Amith Yamasani4f582632014-02-19 14:31:52 -080053import android.os.UserHandle;
Amith Yamasanie781c812014-05-28 15:28:18 -070054import android.os.UserManager;
Makoto Onuki04b9aab2016-05-23 17:13:30 -070055import android.util.DisplayMetrics;
Amith Yamasani4f582632014-02-19 14:31:52 -080056import android.util.Log;
57
Makoto Onuki7c7fbf62017-04-14 11:03:56 -070058import com.android.internal.util.Preconditions;
59
Makoto Onuki04b9aab2016-05-23 17:13:30 -070060import java.io.IOException;
Makoto Onuki6f7362d92016-03-04 13:39:41 -080061import java.lang.annotation.Retention;
62import java.lang.annotation.RetentionPolicy;
Amith Yamasani4f582632014-02-19 14:31:52 -080063import java.util.ArrayList;
Makoto Onukib6d35232016-04-04 15:57:17 -070064import java.util.Arrays;
Amith Yamasani4f582632014-02-19 14:31:52 -080065import java.util.Collections;
66import java.util.List;
67
68/**
69 * Class for retrieving a list of launchable activities for the current user and any associated
Makoto Onukiaecbd032017-01-19 12:11:11 -080070 * managed profiles that are visible to the current user, which can be retrieved with
71 * {@link #getProfiles}. This is mainly for use by launchers.
72 *
73 * Apps can be queried for each user profile.
Amith Yamasani4f582632014-02-19 14:31:52 -080074 * Since the PackageManager will not deliver package broadcasts for other profiles, you can register
75 * for package changes here.
Amith Yamasanie781c812014-05-28 15:28:18 -070076 * <p>
77 * To watch for managed profiles being added or removed, register for the following broadcasts:
78 * {@link Intent#ACTION_MANAGED_PROFILE_ADDED} and {@link Intent#ACTION_MANAGED_PROFILE_REMOVED}.
79 * <p>
Makoto Onukiaecbd032017-01-19 12:11:11 -080080 * Note as of Android O, apps on a managed profile are no longer allowed to access apps on the
81 * main profile. Apps can only access profiles returned by {@link #getProfiles()}.
Amith Yamasani4f582632014-02-19 14:31:52 -080082 */
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -060083@SystemService(Context.LAUNCHER_APPS_SERVICE)
Amith Yamasani4f582632014-02-19 14:31:52 -080084public class LauncherApps {
85
86 static final String TAG = "LauncherApps";
87 static final boolean DEBUG = false;
88
Makoto Onuki2d895c32016-12-02 15:48:40 -080089 /**
90 * Activity Action: For the default launcher to show the confirmation dialog to create
91 * a pinned shortcut.
92 *
93 * <p>See the {@link ShortcutManager} javadoc for details.
94 *
95 * <p>
96 * Use {@link #getPinItemRequest(Intent)} to get a {@link PinItemRequest} object,
97 * and call {@link PinItemRequest#accept(Bundle)}
98 * if the user accepts. If the user doesn't accept, no further action is required.
99 *
100 * @see #EXTRA_PIN_ITEM_REQUEST
101 */
102 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
Sunny Goyal7f7372a2017-01-24 11:53:54 -0800103 public static final String ACTION_CONFIRM_PIN_SHORTCUT =
104 "android.content.pm.action.CONFIRM_PIN_SHORTCUT";
Makoto Onuki2d895c32016-12-02 15:48:40 -0800105
106 /**
Sunny Goyal7f7372a2017-01-24 11:53:54 -0800107 * Activity Action: For the default launcher to show the confirmation dialog to create
108 * a pinned app widget.
109 *
110 * <p>See the {@link android.appwidget.AppWidgetManager#requestPinAppWidget} javadoc for
111 * details.
112 *
113 * <p>
114 * Use {@link #getPinItemRequest(Intent)} to get a {@link PinItemRequest} object,
115 * and call {@link PinItemRequest#accept(Bundle)}
116 * if the user accepts. If the user doesn't accept, no further action is required.
117 *
118 * @see #EXTRA_PIN_ITEM_REQUEST
119 */
120 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
121 public static final String ACTION_CONFIRM_PIN_APPWIDGET =
122 "android.content.pm.action.CONFIRM_PIN_APPWIDGET";
123
124 /**
125 * An extra for {@link #ACTION_CONFIRM_PIN_SHORTCUT} &amp; {@link #ACTION_CONFIRM_PIN_APPWIDGET}
126 * containing a {@link PinItemRequest} of appropriate type asked to pin.
Makoto Onuki2d895c32016-12-02 15:48:40 -0800127 *
128 * <p>A helper function {@link #getPinItemRequest(Intent)} can be used
129 * instead of using this constant directly.
130 *
Sunny Goyal7f7372a2017-01-24 11:53:54 -0800131 * @see #ACTION_CONFIRM_PIN_SHORTCUT
132 * @see #ACTION_CONFIRM_PIN_APPWIDGET
Makoto Onuki2d895c32016-12-02 15:48:40 -0800133 */
134 public static final String EXTRA_PIN_ITEM_REQUEST =
135 "android.content.pm.extra.PIN_ITEM_REQUEST";
136
Makoto Onukide3c16c2017-01-26 11:39:31 -0800137 private final Context mContext;
138 private final ILauncherApps mService;
139 private final PackageManager mPm;
140 private final UserManager mUserManager;
Amith Yamasani4f582632014-02-19 14:31:52 -0800141
Kenny Guyb42c89b2014-07-28 19:20:07 +0100142 private List<CallbackMessageHandler> mCallbacks
143 = new ArrayList<CallbackMessageHandler>();
Kenny Guyc01545372014-06-16 14:17:26 +0100144
145 /**
146 * Callbacks for package changes to this and related managed profiles.
147 */
Kenny Guyf939dba2014-08-15 15:32:34 +0100148 public static abstract class Callback {
Kenny Guyc01545372014-06-16 14:17:26 +0100149 /**
150 * Indicates that a package was removed from the specified profile.
151 *
Kenny Guyb42c89b2014-07-28 19:20:07 +0100152 * If a package is removed while being updated onPackageChanged will be
153 * called instead.
154 *
Kenny Guyc01545372014-06-16 14:17:26 +0100155 * @param packageName The name of the package that was removed.
156 * @param user The UserHandle of the profile that generated the change.
157 */
158 abstract public void onPackageRemoved(String packageName, UserHandle user);
159
160 /**
161 * Indicates that a package was added to the specified profile.
162 *
Kenny Guyb42c89b2014-07-28 19:20:07 +0100163 * If a package is added while being updated then onPackageChanged will be
164 * called instead.
165 *
Kenny Guyc01545372014-06-16 14:17:26 +0100166 * @param packageName The name of the package that was added.
167 * @param user The UserHandle of the profile that generated the change.
168 */
169 abstract public void onPackageAdded(String packageName, UserHandle user);
170
171 /**
172 * Indicates that a package was modified in the specified profile.
Kenny Guyb42c89b2014-07-28 19:20:07 +0100173 * This can happen, for example, when the package is updated or when
174 * one or more components are enabled or disabled.
Kenny Guyc01545372014-06-16 14:17:26 +0100175 *
176 * @param packageName The name of the package that has changed.
177 * @param user The UserHandle of the profile that generated the change.
178 */
179 abstract public void onPackageChanged(String packageName, UserHandle user);
180
181 /**
182 * Indicates that one or more packages have become available. For
183 * example, this can happen when a removable storage card has
184 * reappeared.
185 *
186 * @param packageNames The names of the packages that have become
187 * available.
188 * @param user The UserHandle of the profile that generated the change.
189 * @param replacing Indicates whether these packages are replacing
190 * existing ones.
191 */
192 abstract public void onPackagesAvailable(String[] packageNames, UserHandle user,
193 boolean replacing);
194
195 /**
196 * Indicates that one or more packages have become unavailable. For
197 * example, this can happen when a removable storage card has been
198 * removed.
199 *
200 * @param packageNames The names of the packages that have become
201 * unavailable.
202 * @param user The UserHandle of the profile that generated the change.
203 * @param replacing Indicates whether the packages are about to be
204 * replaced with new versions.
205 */
206 abstract public void onPackagesUnavailable(String[] packageNames, UserHandle user,
207 boolean replacing);
Kenny Guy77242752016-01-15 13:29:06 +0000208
209 /**
210 * Indicates that one or more packages have been suspended. For
211 * example, this can happen when a Device Administrator suspends
212 * an applicaton.
213 *
Suprabh Shukla19b41f32018-03-26 22:35:13 -0700214 * <p>Note: On devices running {@link android.os.Build.VERSION_CODES#P Android P} or higher,
Suprabh Shukla96212bc2018-04-10 15:04:51 -0700215 * any apps that override {@link #onPackagesSuspended(String[], UserHandle, Bundle)} will
Suprabh Shukla19b41f32018-03-26 22:35:13 -0700216 * not receive this callback.
217 *
Kenny Guy77242752016-01-15 13:29:06 +0000218 * @param packageNames The names of the packages that have just been
219 * suspended.
220 * @param user The UserHandle of the profile that generated the change.
221 */
222 public void onPackagesSuspended(String[] packageNames, UserHandle user) {
223 }
224
225 /**
Suprabh Shukla19b41f32018-03-26 22:35:13 -0700226 * Indicates that one or more packages have been suspended. A device administrator or an app
227 * with {@code android.permission.SUSPEND_APPS} can do this.
228 *
Suprabh Shukla96212bc2018-04-10 15:04:51 -0700229 * <p>A suspending app with the permission {@code android.permission.SUSPEND_APPS} can
230 * optionally provide a {@link Bundle} of extra information that it deems helpful for the
231 * launcher to handle the suspended state of these packages. The contents of this
232 * {@link Bundle} supposed to be a contract between the suspending app and the launcher.
Suprabh Shukla19b41f32018-03-26 22:35:13 -0700233 *
Suprabh Shukla96212bc2018-04-10 15:04:51 -0700234 * @param packageNames The names of the packages that have just been suspended.
235 * @param user the user for which the given packages were suspended.
236 * @param launcherExtras A {@link Bundle} of extras for the launcher, if provided to the
237 * system, {@code null} otherwise.
Suprabh Shukla19b41f32018-03-26 22:35:13 -0700238 * @see PackageManager#isPackageSuspended()
239 * @see #getSuspendedPackageLauncherExtras(String, UserHandle)
240 */
Suprabh Shukla96212bc2018-04-10 15:04:51 -0700241 public void onPackagesSuspended(String[] packageNames, UserHandle user,
242 @Nullable Bundle launcherExtras) {
Suprabh Shukla19b41f32018-03-26 22:35:13 -0700243 onPackagesSuspended(packageNames, user);
244 }
245
246 /**
Kenny Guy77242752016-01-15 13:29:06 +0000247 * Indicates that one or more packages have been unsuspended. For
248 * example, this can happen when a Device Administrator unsuspends
249 * an applicaton.
250 *
251 * @param packageNames The names of the packages that have just been
252 * unsuspended.
253 * @param user The UserHandle of the profile that generated the change.
254 */
255 public void onPackagesUnsuspended(String[] packageNames, UserHandle user) {
256 }
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800257
258 /**
Makoto Onukife9c9662016-07-25 15:12:23 -0700259 * Indicates that one or more shortcuts of any kind (dynamic, pinned, or manifest)
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800260 * have been added, updated or removed.
261 *
Makoto Onuki2d5b4652016-03-11 16:09:54 -0800262 * <p>Only the applications that are allowed to access the shortcut information,
263 * as defined in {@link #hasShortcutHostPermission()}, will receive it.
264 *
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800265 * @param packageName The name of the package that has the shortcuts.
Makoto Onukife9c9662016-07-25 15:12:23 -0700266 * @param shortcuts All shortcuts from the package (dynamic, manifest and/or pinned).
267 * Only "key" information will be provided, as defined in
Makoto Onuki4d6b87f2016-06-17 13:47:40 -0700268 * {@link ShortcutInfo#hasKeyFieldsOnly()}.
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800269 * @param user The UserHandle of the profile that generated the change.
Makoto Onuki4a910962016-07-07 13:57:34 -0700270 *
271 * @see ShortcutManager
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800272 */
273 public void onShortcutsChanged(@NonNull String packageName,
274 @NonNull List<ShortcutInfo> shortcuts, @NonNull UserHandle user) {
275 }
276 }
277
278 /**
279 * Represents a query passed to {@link #getShortcuts(ShortcutQuery, UserHandle)}.
280 */
281 public static class ShortcutQuery {
282 /**
283 * Include dynamic shortcuts in the result.
284 */
Makoto Onukib5a012f2016-06-21 11:13:53 -0700285 public static final int FLAG_MATCH_DYNAMIC = 1 << 0;
286
287 /** @hide kept for unit tests */
288 @Deprecated
289 public static final int FLAG_GET_DYNAMIC = FLAG_MATCH_DYNAMIC;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800290
291 /**
292 * Include pinned shortcuts in the result.
Makoto Onuki88b4dcc2017-12-07 15:53:56 -0800293 *
294 * <p>If you are the selected assistant app, and wishes to fetch all shortcuts that the
295 * user owns on the launcher (or by other launchers, in case the user has multiple), use
296 * {@link #FLAG_MATCH_PINNED_BY_ANY_LAUNCHER} instead.
297 *
298 * <p>If you're a regular launcher app, there's no way to get shortcuts pinned by other
299 * launchers, and {@link #FLAG_MATCH_PINNED_BY_ANY_LAUNCHER} will be ignored. So use this
300 * flag to get own pinned shortcuts.
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800301 */
Makoto Onukib5a012f2016-06-21 11:13:53 -0700302 public static final int FLAG_MATCH_PINNED = 1 << 1;
303
304 /** @hide kept for unit tests */
305 @Deprecated
306 public static final int FLAG_GET_PINNED = FLAG_MATCH_PINNED;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800307
308 /**
Makoto Onuki22fcc682016-05-17 14:52:19 -0700309 * Include manifest shortcuts in the result.
310 */
Makoto Onukib5a012f2016-06-21 11:13:53 -0700311 public static final int FLAG_MATCH_MANIFEST = 1 << 3;
312
313 /** @hide kept for unit tests */
314 @Deprecated
315 public static final int FLAG_GET_MANIFEST = FLAG_MATCH_MANIFEST;
Makoto Onuki22fcc682016-05-17 14:52:19 -0700316
Hakan Seyalioglu58fc95d2016-12-13 15:23:22 -0800317 /**
Makoto Onuki35559d62017-11-06 16:26:32 -0800318 * Include all pinned shortcuts by any launchers, not just by the caller,
Makoto Onuki634cecb2017-10-13 17:10:48 -0700319 * in the result.
Makoto Onuki35559d62017-11-06 16:26:32 -0800320 *
Makoto Onuki88b4dcc2017-12-07 15:53:56 -0800321 * <p>The caller must be the selected assistant app to use this flag, or have the system
Makoto Onuki35559d62017-11-06 16:26:32 -0800322 * {@code ACCESS_SHORTCUTS} permission.
Makoto Onuki88b4dcc2017-12-07 15:53:56 -0800323 *
324 * <p>If you are the selected assistant app, and wishes to fetch all shortcuts that the
325 * user owns on the launcher (or by other launchers, in case the user has multiple), use
326 * {@link #FLAG_MATCH_PINNED_BY_ANY_LAUNCHER} instead.
327 *
328 * <p>If you're a regular launcher app (or any app that's not the selected assistant app)
329 * then this flag will be ignored.
Makoto Onuki634cecb2017-10-13 17:10:48 -0700330 */
Makoto Onuki35559d62017-11-06 16:26:32 -0800331 public static final int FLAG_MATCH_PINNED_BY_ANY_LAUNCHER = 1 << 10;
Makoto Onuki634cecb2017-10-13 17:10:48 -0700332
333 /**
334 * FLAG_MATCH_DYNAMIC | FLAG_MATCH_PINNED | FLAG_MATCH_MANIFEST
Hakan Seyalioglu58fc95d2016-12-13 15:23:22 -0800335 * @hide
336 */
Makoto Onukib5a012f2016-06-21 11:13:53 -0700337 public static final int FLAG_MATCH_ALL_KINDS =
Makoto Onuki634cecb2017-10-13 17:10:48 -0700338 FLAG_MATCH_DYNAMIC | FLAG_MATCH_PINNED | FLAG_MATCH_MANIFEST;
339
340 /**
341 * FLAG_MATCH_DYNAMIC | FLAG_MATCH_PINNED | FLAG_MATCH_MANIFEST | FLAG_MATCH_ALL_PINNED
342 * @hide
343 */
344 public static final int FLAG_MATCH_ALL_KINDS_WITH_ALL_PINNED =
Makoto Onuki35559d62017-11-06 16:26:32 -0800345 FLAG_MATCH_ALL_KINDS | FLAG_MATCH_PINNED_BY_ANY_LAUNCHER;
Makoto Onuki4d6b87f2016-06-17 13:47:40 -0700346
Makoto Onukib5a012f2016-06-21 11:13:53 -0700347 /** @hide kept for unit tests */
348 @Deprecated
349 public static final int FLAG_GET_ALL_KINDS = FLAG_MATCH_ALL_KINDS;
350
Makoto Onuki22fcc682016-05-17 14:52:19 -0700351 /**
Makoto Onukife9c9662016-07-25 15:12:23 -0700352 * Requests "key" fields only. See {@link ShortcutInfo#hasKeyFieldsOnly()}'s javadoc to
353 * see which fields fields "key".
354 * This allows quicker access to shortcut information in order to
355 * determine whether the caller's in-memory cache needs to be updated.
Makoto Onuki4a910962016-07-07 13:57:34 -0700356 *
Makoto Onukife9c9662016-07-25 15:12:23 -0700357 * <p>Typically, launcher applications cache all or most shortcut information
358 * in memory in order to show shortcuts without a delay.
359 *
360 * When a given launcher application wants to update its cache, such as when its process
361 * restarts, it can fetch shortcut information with this flag.
362 * The application can then check {@link ShortcutInfo#getLastChangedTimestamp()} for each
363 * shortcut, fetching a shortcut's non-key information only if that shortcut has been
364 * updated.
Makoto Onuki4a910962016-07-07 13:57:34 -0700365 *
366 * @see ShortcutManager
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800367 */
368 public static final int FLAG_GET_KEY_FIELDS_ONLY = 1 << 2;
369
370 /** @hide */
Jeff Sharkeyce8db992017-12-13 20:05:05 -0700371 @IntDef(flag = true, prefix = { "FLAG_" }, value = {
372 FLAG_MATCH_DYNAMIC,
373 FLAG_MATCH_PINNED,
374 FLAG_MATCH_MANIFEST,
375 FLAG_GET_KEY_FIELDS_ONLY,
376 FLAG_MATCH_MANIFEST,
377 })
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800378 @Retention(RetentionPolicy.SOURCE)
379 public @interface QueryFlags {}
380
381 long mChangedSince;
382
383 @Nullable
384 String mPackage;
385
386 @Nullable
Makoto Onukiabe84422016-04-07 09:41:19 -0700387 List<String> mShortcutIds;
388
389 @Nullable
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800390 ComponentName mActivity;
391
392 @QueryFlags
393 int mQueryFlags;
394
395 public ShortcutQuery() {
396 }
397
398 /**
Makoto Onukife9c9662016-07-25 15:12:23 -0700399 * If non-zero, returns only shortcuts that have been added or updated
400 * since the given timestamp, expressed in milliseconds since the Epoch&mdash;see
401 * {@link System#currentTimeMillis()}.
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800402 */
Makoto Onuki22fcc682016-05-17 14:52:19 -0700403 public ShortcutQuery setChangedSince(long changedSince) {
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800404 mChangedSince = changedSince;
Makoto Onuki22fcc682016-05-17 14:52:19 -0700405 return this;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800406 }
407
408 /**
409 * If non-null, returns only shortcuts from the package.
410 */
Makoto Onuki22fcc682016-05-17 14:52:19 -0700411 public ShortcutQuery setPackage(@Nullable String packageName) {
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800412 mPackage = packageName;
Makoto Onuki22fcc682016-05-17 14:52:19 -0700413 return this;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800414 }
415
416 /**
Makoto Onukiabe84422016-04-07 09:41:19 -0700417 * If non-null, return only the specified shortcuts by ID. When setting this field,
Makoto Onuki4a910962016-07-07 13:57:34 -0700418 * a package name must also be set with {@link #setPackage}.
Makoto Onukiabe84422016-04-07 09:41:19 -0700419 */
Makoto Onuki22fcc682016-05-17 14:52:19 -0700420 public ShortcutQuery setShortcutIds(@Nullable List<String> shortcutIds) {
Makoto Onukiabe84422016-04-07 09:41:19 -0700421 mShortcutIds = shortcutIds;
Makoto Onuki22fcc682016-05-17 14:52:19 -0700422 return this;
Makoto Onukiabe84422016-04-07 09:41:19 -0700423 }
424
425 /**
Makoto Onuki22fcc682016-05-17 14:52:19 -0700426 * If non-null, returns only shortcuts associated with the activity; i.e.
427 * {@link ShortcutInfo}s whose {@link ShortcutInfo#getActivity()} are equal
428 * to {@code activity}.
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800429 */
Makoto Onuki22fcc682016-05-17 14:52:19 -0700430 public ShortcutQuery setActivity(@Nullable ComponentName activity) {
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800431 mActivity = activity;
Makoto Onuki22fcc682016-05-17 14:52:19 -0700432 return this;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800433 }
434
Hakan Seyalioglu58fc95d2016-12-13 15:23:22 -0800435 /**
Makoto Onukife9c9662016-07-25 15:12:23 -0700436 * Set query options. At least one of the {@code MATCH} flags should be set. Otherwise,
437 * no shortcuts will be returned.
Makoto Onuki4a910962016-07-07 13:57:34 -0700438 *
Makoto Onukife9c9662016-07-25 15:12:23 -0700439 * <ul>
440 * <li>{@link #FLAG_MATCH_DYNAMIC}
441 * <li>{@link #FLAG_MATCH_PINNED}
442 * <li>{@link #FLAG_MATCH_MANIFEST}
443 * <li>{@link #FLAG_GET_KEY_FIELDS_ONLY}
444 * </ul>
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800445 */
Makoto Onuki22fcc682016-05-17 14:52:19 -0700446 public ShortcutQuery setQueryFlags(@QueryFlags int queryFlags) {
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800447 mQueryFlags = queryFlags;
Makoto Onuki22fcc682016-05-17 14:52:19 -0700448 return this;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800449 }
Kenny Guyc01545372014-06-16 14:17:26 +0100450 }
Amith Yamasani4f582632014-02-19 14:31:52 -0800451
Amith Yamasani4f582632014-02-19 14:31:52 -0800452 /** @hide */
453 public LauncherApps(Context context, ILauncherApps service) {
454 mContext = context;
455 mService = service;
Amith Yamasanie781c812014-05-28 15:28:18 -0700456 mPm = context.getPackageManager();
Makoto Onukide3c16c2017-01-26 11:39:31 -0800457 mUserManager = context.getSystemService(UserManager.class);
Amith Yamasani4f582632014-02-19 14:31:52 -0800458 }
459
Makoto Onuki5ba0d3e2016-04-11 14:03:46 -0700460 /** @hide */
461 @TestApi
462 public LauncherApps(Context context) {
463 this(context, ILauncherApps.Stub.asInterface(
464 ServiceManager.getService(Context.LAUNCHER_APPS_SERVICE)));
465 }
466
Amith Yamasani4f582632014-02-19 14:31:52 -0800467 /**
Makoto Onukide3c16c2017-01-26 11:39:31 -0800468 * Show an error log on logcat, when the calling user is a managed profile, and the target
469 * user is different from the calling user, in order to help developers to detect it.
470 */
471 private void logErrorForInvalidProfileAccess(@NonNull UserHandle target) {
472 if (UserHandle.myUserId() != target.getIdentifier() && mUserManager.isManagedProfile()) {
Makoto Onuki3cc7cd12017-04-03 12:48:42 -0700473 Log.w(TAG, "Accessing other profiles/users from managed profile is no longer allowed.");
Makoto Onukide3c16c2017-01-26 11:39:31 -0800474 }
475 }
476
477 /**
Makoto Onukiaecbd032017-01-19 12:11:11 -0800478 * Return a list of profiles that the caller can access via the {@link LauncherApps} APIs.
479 *
480 * <p>If the caller is running on a managed profile, it'll return only the current profile.
481 * Otherwise it'll return the same list as {@link UserManager#getUserProfiles()} would.
482 */
483 public List<UserHandle> getProfiles() {
Makoto Onukide3c16c2017-01-26 11:39:31 -0800484 if (mUserManager.isManagedProfile()) {
Makoto Onukiaecbd032017-01-19 12:11:11 -0800485 // If it's a managed profile, only return the current profile.
486 final List result = new ArrayList(1);
487 result.add(android.os.Process.myUserHandle());
488 return result;
489 } else {
Makoto Onukide3c16c2017-01-26 11:39:31 -0800490 return mUserManager.getUserProfiles();
Makoto Onukiaecbd032017-01-19 12:11:11 -0800491 }
492 }
493
494 /**
Amith Yamasani4f582632014-02-19 14:31:52 -0800495 * Retrieves a list of launchable activities that match {@link Intent#ACTION_MAIN} and
496 * {@link Intent#CATEGORY_LAUNCHER}, for a specified user.
497 *
498 * @param packageName The specific package to query. If null, it checks all installed packages
499 * in the profile.
500 * @param user The UserHandle of the profile.
501 * @return List of launchable activities. Can be an empty list but will not be null.
502 */
503 public List<LauncherActivityInfo> getActivityList(String packageName, UserHandle user) {
Makoto Onukide3c16c2017-01-26 11:39:31 -0800504 logErrorForInvalidProfileAccess(user);
Amith Yamasani4f582632014-02-19 14:31:52 -0800505 try {
Makoto Onuki3a2541e2017-01-24 09:00:15 -0800506 return convertToActivityList(mService.getLauncherActivities(mContext.getPackageName(),
507 packageName, user), user);
Amith Yamasani4f582632014-02-19 14:31:52 -0800508 } catch (RemoteException re) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700509 throw re.rethrowFromSystemServer();
Amith Yamasani4f582632014-02-19 14:31:52 -0800510 }
Amith Yamasani4f582632014-02-19 14:31:52 -0800511 }
512
Amith Yamasani4f582632014-02-19 14:31:52 -0800513 /**
514 * Returns the activity info for a given intent and user handle, if it resolves. Otherwise it
515 * returns null.
516 *
517 * @param intent The intent to find a match for.
518 * @param user The profile to look in for a match.
519 * @return An activity info object if there is a match.
520 */
521 public LauncherActivityInfo resolveActivity(Intent intent, UserHandle user) {
Makoto Onukide3c16c2017-01-26 11:39:31 -0800522 logErrorForInvalidProfileAccess(user);
Amith Yamasani4f582632014-02-19 14:31:52 -0800523 try {
Makoto Onuki3a2541e2017-01-24 09:00:15 -0800524 ActivityInfo ai = mService.resolveActivity(mContext.getPackageName(),
525 intent.getComponent(), user);
Sunny Goyal45d3e972016-03-31 12:38:17 -0700526 if (ai != null) {
527 LauncherActivityInfo info = new LauncherActivityInfo(mContext, ai, user);
Amith Yamasani4f582632014-02-19 14:31:52 -0800528 return info;
529 }
530 } catch (RemoteException re) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700531 throw re.rethrowFromSystemServer();
Amith Yamasani4f582632014-02-19 14:31:52 -0800532 }
533 return null;
534 }
535
536 /**
Kenny Guyf939dba2014-08-15 15:32:34 +0100537 * Starts a Main activity in the specified profile.
Amith Yamasani4f582632014-02-19 14:31:52 -0800538 *
539 * @param component The ComponentName of the activity to launch
Amith Yamasanie781c812014-05-28 15:28:18 -0700540 * @param user The UserHandle of the profile
541 * @param sourceBounds The Rect containing the source bounds of the clicked icon
542 * @param opts Options to pass to startActivity
543 */
Kenny Guyf939dba2014-08-15 15:32:34 +0100544 public void startMainActivity(ComponentName component, UserHandle user, Rect sourceBounds,
Amith Yamasanie781c812014-05-28 15:28:18 -0700545 Bundle opts) {
Makoto Onukide3c16c2017-01-26 11:39:31 -0800546 logErrorForInvalidProfileAccess(user);
Amith Yamasani5abdbb62014-04-08 17:23:46 -0700547 if (DEBUG) {
Kenny Guyf939dba2014-08-15 15:32:34 +0100548 Log.i(TAG, "StartMainActivity " + component + " " + user.getIdentifier());
Amith Yamasani5abdbb62014-04-08 17:23:46 -0700549 }
Amith Yamasani4f582632014-02-19 14:31:52 -0800550 try {
Makoto Onuki3a2541e2017-01-24 09:00:15 -0800551 mService.startActivityAsUser(mContext.getPackageName(),
552 component, sourceBounds, opts, user);
Amith Yamasani4f582632014-02-19 14:31:52 -0800553 } catch (RemoteException re) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700554 throw re.rethrowFromSystemServer();
Amith Yamasani4f582632014-02-19 14:31:52 -0800555 }
556 }
557
558 /**
Kenny Guy466d2032014-07-23 12:23:35 +0100559 * Starts the settings activity to show the application details for a
560 * package in the specified profile.
561 *
562 * @param component The ComponentName of the package to launch settings for.
563 * @param user The UserHandle of the profile
564 * @param sourceBounds The Rect containing the source bounds of the clicked icon
565 * @param opts Options to pass to startActivity
566 */
Kenny Guyf939dba2014-08-15 15:32:34 +0100567 public void startAppDetailsActivity(ComponentName component, UserHandle user,
Kenny Guy466d2032014-07-23 12:23:35 +0100568 Rect sourceBounds, Bundle opts) {
Makoto Onukide3c16c2017-01-26 11:39:31 -0800569 logErrorForInvalidProfileAccess(user);
Kenny Guy466d2032014-07-23 12:23:35 +0100570 try {
Makoto Onuki3a2541e2017-01-24 09:00:15 -0800571 mService.showAppDetailsAsUser(mContext.getPackageName(),
572 component, sourceBounds, opts, user);
Kenny Guy466d2032014-07-23 12:23:35 +0100573 } catch (RemoteException re) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700574 throw re.rethrowFromSystemServer();
Kenny Guy466d2032014-07-23 12:23:35 +0100575 }
576 }
577
578 /**
Sunny Goyala6be88a2017-01-12 16:27:58 -0800579 * Retrieves a list of config activities for creating {@link ShortcutInfo}.
580 *
581 * @param packageName The specific package to query. If null, it checks all installed packages
582 * in the profile.
583 * @param user The UserHandle of the profile.
584 * @return List of config activities. Can be an empty list but will not be null.
585 *
586 * @see Intent#ACTION_CREATE_SHORTCUT
587 * @see #getShortcutConfigActivityIntent(LauncherActivityInfo)
588 */
589 public List<LauncherActivityInfo> getShortcutConfigActivityList(@Nullable String packageName,
590 @NonNull UserHandle user) {
Makoto Onukide3c16c2017-01-26 11:39:31 -0800591 logErrorForInvalidProfileAccess(user);
Sunny Goyala6be88a2017-01-12 16:27:58 -0800592 try {
Makoto Onuki3a2541e2017-01-24 09:00:15 -0800593 return convertToActivityList(mService.getShortcutConfigActivities(
594 mContext.getPackageName(), packageName, user),
Sunny Goyala6be88a2017-01-12 16:27:58 -0800595 user);
596 } catch (RemoteException re) {
597 throw re.rethrowFromSystemServer();
598 }
599 }
600
601 private List<LauncherActivityInfo> convertToActivityList(
602 @Nullable ParceledListSlice<ResolveInfo> activities, UserHandle user) {
603 if (activities == null) {
604 return Collections.EMPTY_LIST;
605 }
606 ArrayList<LauncherActivityInfo> lais = new ArrayList<>();
607 for (ResolveInfo ri : activities.getList()) {
608 LauncherActivityInfo lai = new LauncherActivityInfo(mContext, ri.activityInfo, user);
609 if (DEBUG) {
610 Log.v(TAG, "Returning activity for profile " + user + " : "
611 + lai.getComponentName());
612 }
613 lais.add(lai);
614 }
615 return lais;
616 }
617
618 /**
619 * Returns an intent sender which can be used to start the configure activity for creating
620 * custom shortcuts. Use this method if the provider is in another profile as you are not
621 * allowed to start an activity in another profile.
622 *
623 * <p>The caller should receive {@link PinItemRequest} in onActivityResult on
624 * {@link android.app.Activity#RESULT_OK}.
625 *
626 * <p>Callers must be allowed to access the shortcut information, as defined in {@link
627 * #hasShortcutHostPermission()}.
628 *
629 * @param info a configuration activity returned by {@link #getShortcutConfigActivityList}
630 *
631 * @throws IllegalStateException when the user is locked or not running.
632 * @throws SecurityException if {@link #hasShortcutHostPermission()} is false.
633 *
634 * @see #getPinItemRequest(Intent)
635 * @see Intent#ACTION_CREATE_SHORTCUT
636 * @see android.app.Activity#startIntentSenderForResult
637 */
Makoto Onukide3c16c2017-01-26 11:39:31 -0800638 @Nullable
Sunny Goyala6be88a2017-01-12 16:27:58 -0800639 public IntentSender getShortcutConfigActivityIntent(@NonNull LauncherActivityInfo info) {
640 try {
641 return mService.getShortcutConfigActivityIntent(
642 mContext.getPackageName(), info.getComponentName(), info.getUser());
643 } catch (RemoteException re) {
644 throw re.rethrowFromSystemServer();
645 }
646 }
647
648 /**
Kenny Guy53fa4ec2014-04-29 14:24:18 +0100649 * Checks if the package is installed and enabled for a profile.
650 *
651 * @param packageName The package to check.
652 * @param user The UserHandle of the profile.
653 *
654 * @return true if the package exists and is enabled.
655 */
Kenny Guyf939dba2014-08-15 15:32:34 +0100656 public boolean isPackageEnabled(String packageName, UserHandle user) {
Makoto Onukide3c16c2017-01-26 11:39:31 -0800657 logErrorForInvalidProfileAccess(user);
Kenny Guy53fa4ec2014-04-29 14:24:18 +0100658 try {
Makoto Onuki3a2541e2017-01-24 09:00:15 -0800659 return mService.isPackageEnabled(mContext.getPackageName(), packageName, user);
Kenny Guy53fa4ec2014-04-29 14:24:18 +0100660 } catch (RemoteException re) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700661 throw re.rethrowFromSystemServer();
Kenny Guy53fa4ec2014-04-29 14:24:18 +0100662 }
663 }
664
665 /**
Suprabh Shukla19b41f32018-03-26 22:35:13 -0700666 * Gets the launcher extras supplied to the system when the given package was suspended via
667 * {@code PackageManager#setPackagesSuspended(String[], boolean, PersistableBundle,
668 * PersistableBundle, String)}.
669 *
Suprabh Shukla96212bc2018-04-10 15:04:51 -0700670 * <p>The contents of this {@link Bundle} are supposed to be a contract between the suspending
671 * app and the launcher.
672 *
Suprabh Shukla19b41f32018-03-26 22:35:13 -0700673 * <p>Note: This just returns whatever extras were provided to the system, <em>which might
674 * even be {@code null}.</em>
675 *
676 * @param packageName The package for which to fetch the launcher extras.
677 * @param user The {@link UserHandle} of the profile.
678 * @return A {@link Bundle} of launcher extras. Or {@code null} if the package is not currently
679 * suspended.
680 *
Suprabh Shukla96212bc2018-04-10 15:04:51 -0700681 * @see Callback#onPackagesSuspended(String[], UserHandle, Bundle)
Suprabh Shukla19b41f32018-03-26 22:35:13 -0700682 * @see PackageManager#isPackageSuspended()
683 */
684 public @Nullable Bundle getSuspendedPackageLauncherExtras(String packageName, UserHandle user) {
685 logErrorForInvalidProfileAccess(user);
686 try {
687 return mService.getSuspendedPackageLauncherExtras(packageName, user);
688 } catch (RemoteException re) {
689 throw re.rethrowFromSystemServer();
690 }
691 }
692
693 /**
Benjamin Miller7afa84c2017-07-17 13:01:35 +0200694 * Returns {@link ApplicationInfo} about an application installed for a specific user profile.
Kenny Guy77242752016-01-15 13:29:06 +0000695 *
Amith Yamasani0d1fd8d2016-10-12 14:21:51 -0700696 * @param packageName The package name of the application
Kenny Guy77242752016-01-15 13:29:06 +0000697 * @param flags Additional option flags {@link PackageManager#getApplicationInfo}
698 * @param user The UserHandle of the profile.
699 *
Benjamin Miller7afa84c2017-07-17 13:01:35 +0200700 * @return {@link ApplicationInfo} containing information about the package. Returns
701 * {@code null} if the package isn't installed for the given profile, or the profile
702 * isn't enabled.
Kenny Guy77242752016-01-15 13:29:06 +0000703 */
Makoto Onuki7c7fbf62017-04-14 11:03:56 -0700704 public ApplicationInfo getApplicationInfo(@NonNull String packageName,
705 @ApplicationInfoFlags int flags, @NonNull UserHandle user)
706 throws PackageManager.NameNotFoundException {
707 Preconditions.checkNotNull(packageName, "packageName");
Suprabh Shukla19b41f32018-03-26 22:35:13 -0700708 Preconditions.checkNotNull(user, "user");
Makoto Onukide3c16c2017-01-26 11:39:31 -0800709 logErrorForInvalidProfileAccess(user);
Kenny Guy77242752016-01-15 13:29:06 +0000710 try {
Makoto Onuki7c7fbf62017-04-14 11:03:56 -0700711 final ApplicationInfo ai = mService
712 .getApplicationInfo(mContext.getPackageName(), packageName, flags, user);
713 if (ai == null) {
714 throw new NameNotFoundException("Package " + packageName + " not found for user "
715 + user.getIdentifier());
716 }
717 return ai;
Kenny Guy77242752016-01-15 13:29:06 +0000718 } catch (RemoteException re) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700719 throw re.rethrowFromSystemServer();
Kenny Guy77242752016-01-15 13:29:06 +0000720 }
721 }
722
723 /**
Kenny Guy53fa4ec2014-04-29 14:24:18 +0100724 * Checks if the activity exists and it enabled for a profile.
725 *
726 * @param component The activity to check.
727 * @param user The UserHandle of the profile.
728 *
729 * @return true if the activity exists and is enabled.
730 */
Kenny Guyf939dba2014-08-15 15:32:34 +0100731 public boolean isActivityEnabled(ComponentName component, UserHandle user) {
Makoto Onukide3c16c2017-01-26 11:39:31 -0800732 logErrorForInvalidProfileAccess(user);
Kenny Guy53fa4ec2014-04-29 14:24:18 +0100733 try {
Makoto Onuki3a2541e2017-01-24 09:00:15 -0800734 return mService.isActivityEnabled(mContext.getPackageName(), component, user);
Kenny Guy53fa4ec2014-04-29 14:24:18 +0100735 } catch (RemoteException re) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700736 throw re.rethrowFromSystemServer();
Kenny Guy53fa4ec2014-04-29 14:24:18 +0100737 }
738 }
739
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800740 /**
Dianne Hackbornc160fa42017-11-01 16:14:26 -0700741 * Returns whether the caller can access the shortcut information. Access is currently
742 * available to:
Makoto Onuki2d5b4652016-03-11 16:09:54 -0800743 *
Dianne Hackbornc160fa42017-11-01 16:14:26 -0700744 * <ul>
745 * <li>The current launcher (or default launcher if there is no set current launcher).</li>
746 * <li>The currently active voice interaction service.</li>
747 * </ul>
Makoto Onuki2d5b4652016-03-11 16:09:54 -0800748 *
Makoto Onuki4a910962016-07-07 13:57:34 -0700749 * <p>Note when this method returns {@code false}, it may be a temporary situation because
Makoto Onuki2d5b4652016-03-11 16:09:54 -0800750 * the user is trying a new launcher application. The user may decide to change the default
Makoto Onuki4a910962016-07-07 13:57:34 -0700751 * launcher back to the calling application again, so even if a launcher application loses
Makoto Onuki2d5b4652016-03-11 16:09:54 -0800752 * this permission, it does <b>not</b> have to purge pinned shortcut information.
Makoto Onukife9c9662016-07-25 15:12:23 -0700753 * If the calling launcher application contains pinned shortcuts, they will still work,
754 * even though the caller no longer has the shortcut host permission.
Makoto Onuki4a910962016-07-07 13:57:34 -0700755 *
Makoto Onuki02f338e2016-07-29 09:40:40 -0700756 * @throws IllegalStateException when the user is locked.
Makoto Onuki9c850012016-07-26 15:50:50 -0700757 *
Makoto Onuki4a910962016-07-07 13:57:34 -0700758 * @see ShortcutManager
Makoto Onuki2d5b4652016-03-11 16:09:54 -0800759 */
760 public boolean hasShortcutHostPermission() {
761 try {
762 return mService.hasShortcutHostPermission(mContext.getPackageName());
763 } catch (RemoteException re) {
764 throw re.rethrowFromSystemServer();
765 }
766 }
767
Makoto Onukib1588c02017-10-12 15:11:45 -0700768 private List<ShortcutInfo> maybeUpdateDisabledMessage(List<ShortcutInfo> shortcuts) {
769 if (shortcuts == null) {
770 return null;
771 }
772 for (int i = shortcuts.size() - 1; i >= 0; i--) {
773 final ShortcutInfo si = shortcuts.get(i);
774 final String message = ShortcutInfo.getDisabledReasonForRestoreIssue(mContext,
775 si.getDisabledReason());
776 if (message != null) {
777 si.setDisabledMessage(message);
778 }
779 }
780 return shortcuts;
781 }
782
Makoto Onuki2d5b4652016-03-11 16:09:54 -0800783 /**
Makoto Onuki4a910962016-07-07 13:57:34 -0700784 * Returns {@link ShortcutInfo}s that match {@code query}.
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800785 *
Makoto Onuki2d5b4652016-03-11 16:09:54 -0800786 * <p>Callers must be allowed to access the shortcut information, as defined in {@link
787 * #hasShortcutHostPermission()}.
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800788 *
789 * @param query result includes shortcuts matching this query.
790 * @param user The UserHandle of the profile.
791 *
792 * @return the IDs of {@link ShortcutInfo}s that match the query.
Makoto Onuki02f338e2016-07-29 09:40:40 -0700793 * @throws IllegalStateException when the user is locked, or when the {@code user} user
794 * is locked or not running.
Makoto Onuki4a910962016-07-07 13:57:34 -0700795 *
796 * @see ShortcutManager
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800797 */
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800798 @Nullable
799 public List<ShortcutInfo> getShortcuts(@NonNull ShortcutQuery query,
800 @NonNull UserHandle user) {
Makoto Onukide3c16c2017-01-26 11:39:31 -0800801 logErrorForInvalidProfileAccess(user);
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800802 try {
Makoto Onukib1588c02017-10-12 15:11:45 -0700803 // Note this is the only case we need to update the disabled message for shortcuts
804 // that weren't restored.
805 // The restore problem messages are only shown by the user, and publishers will never
806 // see them. The only other API that the launcher gets shortcuts is the shortcut
807 // changed callback, but that only returns shortcuts with the "key" information, so
808 // that won't return disabled message.
809 return maybeUpdateDisabledMessage(mService.getShortcuts(mContext.getPackageName(),
Makoto Onukiabe84422016-04-07 09:41:19 -0700810 query.mChangedSince, query.mPackage, query.mShortcutIds, query.mActivity,
Makoto Onuki99302b52017-03-29 12:42:26 -0700811 query.mQueryFlags, user)
Makoto Onukib1588c02017-10-12 15:11:45 -0700812 .getList());
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800813 } catch (RemoteException e) {
814 throw e.rethrowFromSystemServer();
815 }
816 }
817
818 /**
Makoto Onukiabe84422016-04-07 09:41:19 -0700819 * @hide // No longer used. Use getShortcuts() instead. Kept for unit tests.
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800820 */
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800821 @Nullable
Makoto Onukib5a012f2016-06-21 11:13:53 -0700822 @Deprecated
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800823 public List<ShortcutInfo> getShortcutInfo(@NonNull String packageName,
824 @NonNull List<String> ids, @NonNull UserHandle user) {
Makoto Onukiabe84422016-04-07 09:41:19 -0700825 final ShortcutQuery q = new ShortcutQuery();
826 q.setPackage(packageName);
827 q.setShortcutIds(ids);
Makoto Onuki4d6b87f2016-06-17 13:47:40 -0700828 q.setQueryFlags(ShortcutQuery.FLAG_GET_ALL_KINDS);
Makoto Onukiabe84422016-04-07 09:41:19 -0700829 return getShortcuts(q, user);
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800830 }
831
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800832 /**
833 * Pin shortcuts on a package.
834 *
835 * <p>This API is <b>NOT</b> cumulative; this will replace all pinned shortcuts for the package.
836 * However, different launchers may have different set of pinned shortcuts.
837 *
Makoto Onukife9c9662016-07-25 15:12:23 -0700838 * <p>The calling launcher application must be allowed to access the shortcut information,
839 * as defined in {@link #hasShortcutHostPermission()}.
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800840 *
841 * @param packageName The target package name.
842 * @param shortcutIds The IDs of the shortcut to be pinned.
843 * @param user The UserHandle of the profile.
Makoto Onuki02f338e2016-07-29 09:40:40 -0700844 * @throws IllegalStateException when the user is locked, or when the {@code user} user
845 * is locked or not running.
Makoto Onuki4a910962016-07-07 13:57:34 -0700846 *
847 * @see ShortcutManager
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800848 */
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800849 public void pinShortcuts(@NonNull String packageName, @NonNull List<String> shortcutIds,
850 @NonNull UserHandle user) {
Makoto Onukide3c16c2017-01-26 11:39:31 -0800851 logErrorForInvalidProfileAccess(user);
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800852 try {
853 mService.pinShortcuts(mContext.getPackageName(), packageName, shortcutIds, user);
854 } catch (RemoteException e) {
855 throw e.rethrowFromSystemServer();
856 }
857 }
858
859 /**
Makoto Onukib6d35232016-04-04 15:57:17 -0700860 * @hide kept for testing.
Makoto Onukiabe84422016-04-07 09:41:19 -0700861 */
Makoto Onukib5a012f2016-06-21 11:13:53 -0700862 @Deprecated
Makoto Onukiabe84422016-04-07 09:41:19 -0700863 public int getShortcutIconResId(@NonNull ShortcutInfo shortcut) {
Makoto Onukib6d35232016-04-04 15:57:17 -0700864 return shortcut.getIconResourceId();
Makoto Onukiabe84422016-04-07 09:41:19 -0700865 }
866
867 /**
Makoto Onukib6d35232016-04-04 15:57:17 -0700868 * @hide kept for testing.
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800869 */
Makoto Onukib5a012f2016-06-21 11:13:53 -0700870 @Deprecated
Makoto Onukiabe84422016-04-07 09:41:19 -0700871 public int getShortcutIconResId(@NonNull String packageName, @NonNull String shortcutId,
872 @NonNull UserHandle user) {
Makoto Onukib6d35232016-04-04 15:57:17 -0700873 final ShortcutQuery q = new ShortcutQuery();
874 q.setPackage(packageName);
875 q.setShortcutIds(Arrays.asList(shortcutId));
Makoto Onuki4d6b87f2016-06-17 13:47:40 -0700876 q.setQueryFlags(ShortcutQuery.FLAG_GET_ALL_KINDS);
Makoto Onukib6d35232016-04-04 15:57:17 -0700877 final List<ShortcutInfo> shortcuts = getShortcuts(q, user);
Makoto Onukiabe84422016-04-07 09:41:19 -0700878
Makoto Onukib6d35232016-04-04 15:57:17 -0700879 return shortcuts.size() > 0 ? shortcuts.get(0).getIconResourceId() : 0;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800880 }
881
882 /**
Makoto Onukib5a012f2016-06-21 11:13:53 -0700883 * @hide internal/unit tests only
Makoto Onukiabe84422016-04-07 09:41:19 -0700884 */
885 public ParcelFileDescriptor getShortcutIconFd(
886 @NonNull ShortcutInfo shortcut) {
Makoto Onuki22fcc682016-05-17 14:52:19 -0700887 return getShortcutIconFd(shortcut.getPackage(), shortcut.getId(),
Makoto Onukiabe84422016-04-07 09:41:19 -0700888 shortcut.getUserId());
889 }
890
891 /**
Makoto Onukib5a012f2016-06-21 11:13:53 -0700892 * @hide internal/unit tests only
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800893 */
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800894 public ParcelFileDescriptor getShortcutIconFd(
Makoto Onukiabe84422016-04-07 09:41:19 -0700895 @NonNull String packageName, @NonNull String shortcutId, @NonNull UserHandle user) {
896 return getShortcutIconFd(packageName, shortcutId, user.getIdentifier());
897 }
898
899 private ParcelFileDescriptor getShortcutIconFd(
900 @NonNull String packageName, @NonNull String shortcutId, int userId) {
Makoto Onuki55046222016-03-08 10:49:47 -0800901 try {
Makoto Onukiabe84422016-04-07 09:41:19 -0700902 return mService.getShortcutIconFd(mContext.getPackageName(),
903 packageName, shortcutId, userId);
Makoto Onuki55046222016-03-08 10:49:47 -0800904 } catch (RemoteException e) {
905 throw e.rethrowFromSystemServer();
906 }
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800907 }
908
Makoto Onuki04b9aab2016-05-23 17:13:30 -0700909 /**
910 * Returns the icon for this shortcut, without any badging for the profile.
911 *
Makoto Onukife9c9662016-07-25 15:12:23 -0700912 * <p>The calling launcher application must be allowed to access the shortcut information,
913 * as defined in {@link #hasShortcutHostPermission()}.
Makoto Onuki4a910962016-07-07 13:57:34 -0700914 *
Makoto Onuki04b9aab2016-05-23 17:13:30 -0700915 * @param density The preferred density of the icon, zero for default density. Use
916 * density DPI values from {@link DisplayMetrics}.
Makoto Onuki4a910962016-07-07 13:57:34 -0700917 *
918 * @return The drawable associated with the shortcut.
Makoto Onuki02f338e2016-07-29 09:40:40 -0700919 * @throws IllegalStateException when the user is locked, or when the {@code user} user
920 * is locked or not running.
Makoto Onuki4a910962016-07-07 13:57:34 -0700921 *
922 * @see ShortcutManager
Makoto Onuki04b9aab2016-05-23 17:13:30 -0700923 * @see #getShortcutBadgedIconDrawable(ShortcutInfo, int)
924 * @see DisplayMetrics
Makoto Onuki04b9aab2016-05-23 17:13:30 -0700925 */
926 public Drawable getShortcutIconDrawable(@NonNull ShortcutInfo shortcut, int density) {
927 if (shortcut.hasIconFile()) {
928 final ParcelFileDescriptor pfd = getShortcutIconFd(shortcut);
929 if (pfd == null) {
930 return null;
931 }
932 try {
933 final Bitmap bmp = BitmapFactory.decodeFileDescriptor(pfd.getFileDescriptor());
Hyunyoung Songf281e7a2017-02-13 10:57:42 -0800934 if (bmp != null) {
935 BitmapDrawable dr = new BitmapDrawable(mContext.getResources(), bmp);
Hyunyoung Songe4179e22017-03-01 12:51:26 -0800936 if (shortcut.hasAdaptiveBitmap()) {
Hyunyoung Songbe8835e2017-02-17 11:25:08 -0800937 return new AdaptiveIconDrawable(null, dr);
Hyunyoung Songf281e7a2017-02-13 10:57:42 -0800938 } else {
939 return dr;
940 }
941 }
942 return null;
Makoto Onuki04b9aab2016-05-23 17:13:30 -0700943 } finally {
944 try {
945 pfd.close();
946 } catch (IOException ignore) {
947 }
948 }
949 } else if (shortcut.hasIconResource()) {
Makoto Onuki2d895c32016-12-02 15:48:40 -0800950 return loadDrawableResourceFromPackage(shortcut.getPackage(),
951 shortcut.getIconResourceId(), shortcut.getUserHandle(), density);
952 } else if (shortcut.getIcon() != null) {
953 // This happens if a shortcut is pending-approval.
954 final Icon icon = shortcut.getIcon();
955 switch (icon.getType()) {
956 case Icon.TYPE_RESOURCE: {
957 return loadDrawableResourceFromPackage(shortcut.getPackage(),
958 icon.getResId(), shortcut.getUserHandle(), density);
Makoto Onuki04b9aab2016-05-23 17:13:30 -0700959 }
Hyunyoung Songf281e7a2017-02-13 10:57:42 -0800960 case Icon.TYPE_BITMAP:
Hyunyoung Songe4179e22017-03-01 12:51:26 -0800961 case Icon.TYPE_ADAPTIVE_BITMAP: {
Makoto Onuki2d895c32016-12-02 15:48:40 -0800962 return icon.loadDrawable(mContext);
963 }
964 default:
965 return null; // Shouldn't happen though.
Makoto Onuki04b9aab2016-05-23 17:13:30 -0700966 }
967 } else {
968 return null; // Has no icon.
969 }
Makoto Onuki20c95f82016-05-11 16:51:01 -0700970 }
971
Makoto Onuki2d895c32016-12-02 15:48:40 -0800972 private Drawable loadDrawableResourceFromPackage(String packageName, int resId,
973 UserHandle user, int density) {
974 try {
975 if (resId == 0) {
976 return null; // Shouldn't happen but just in case.
977 }
978 final ApplicationInfo ai = getApplicationInfo(packageName, /* flags =*/ 0, user);
979 final Resources res = mContext.getPackageManager().getResourcesForApplication(ai);
980 return res.getDrawableForDensity(resId, density);
981 } catch (NameNotFoundException | Resources.NotFoundException e) {
982 return null;
983 }
984 }
985
Makoto Onuki04b9aab2016-05-23 17:13:30 -0700986 /**
987 * Returns the shortcut icon with badging appropriate for the profile.
988 *
Makoto Onukife9c9662016-07-25 15:12:23 -0700989 * <p>The calling launcher application must be allowed to access the shortcut information,
990 * as defined in {@link #hasShortcutHostPermission()}.
Makoto Onuki4a910962016-07-07 13:57:34 -0700991 *
Makoto Onuki04b9aab2016-05-23 17:13:30 -0700992 * @param density Optional density for the icon, or 0 to use the default density. Use
Makoto Onuki04b9aab2016-05-23 17:13:30 -0700993 * @return A badged icon for the shortcut.
Makoto Onuki02f338e2016-07-29 09:40:40 -0700994 * @throws IllegalStateException when the user is locked, or when the {@code user} user
995 * is locked or not running.
Makoto Onuki4a910962016-07-07 13:57:34 -0700996 *
997 * @see ShortcutManager
Makoto Onukife9c9662016-07-25 15:12:23 -0700998 * @see #getShortcutIconDrawable(ShortcutInfo, int)
Makoto Onuki4a910962016-07-07 13:57:34 -0700999 * @see DisplayMetrics
Makoto Onuki04b9aab2016-05-23 17:13:30 -07001000 */
1001 public Drawable getShortcutBadgedIconDrawable(ShortcutInfo shortcut, int density) {
1002 final Drawable originalIcon = getShortcutIconDrawable(shortcut, density);
1003
1004 return (originalIcon == null) ? null : mContext.getPackageManager().getUserBadgedIcon(
1005 originalIcon, shortcut.getUserHandle());
Makoto Onuki20c95f82016-05-11 16:51:01 -07001006 }
1007
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001008 /**
Makoto Onuki4a910962016-07-07 13:57:34 -07001009 * Starts a shortcut.
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001010 *
Makoto Onukife9c9662016-07-25 15:12:23 -07001011 * <p>The calling launcher application must be allowed to access the shortcut information,
1012 * as defined in {@link #hasShortcutHostPermission()}.
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001013 *
Makoto Onuki43204b82016-03-08 16:16:44 -08001014 * @param packageName The target shortcut package name.
1015 * @param shortcutId The target shortcut ID.
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001016 * @param sourceBounds The Rect containing the source bounds of the clicked icon.
1017 * @param startActivityOptions Options to pass to startActivity.
1018 * @param user The UserHandle of the profile.
Makoto Onuki02f338e2016-07-29 09:40:40 -07001019 * @throws IllegalStateException when the user is locked, or when the {@code user} user
1020 * is locked or not running.
Makoto Onuki83f6d2d2016-07-11 14:30:19 -07001021 *
1022 * @throws android.content.ActivityNotFoundException failed to start shortcut. (e.g.
1023 * the shortcut no longer exists, is disabled, the intent receiver activity doesn't exist, etc)
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001024 */
Makoto Onukid6880792016-06-29 13:37:43 -07001025 public void startShortcut(@NonNull String packageName, @NonNull String shortcutId,
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001026 @Nullable Rect sourceBounds, @Nullable Bundle startActivityOptions,
1027 @NonNull UserHandle user) {
Makoto Onukide3c16c2017-01-26 11:39:31 -08001028 logErrorForInvalidProfileAccess(user);
1029
Makoto Onukid6880792016-06-29 13:37:43 -07001030 startShortcut(packageName, shortcutId, sourceBounds, startActivityOptions,
Makoto Onukiabe84422016-04-07 09:41:19 -07001031 user.getIdentifier());
1032 }
1033
1034 /**
1035 * Launches a shortcut.
1036 *
Makoto Onukife9c9662016-07-25 15:12:23 -07001037 * <p>The calling launcher application must be allowed to access the shortcut information,
1038 * as defined in {@link #hasShortcutHostPermission()}.
Makoto Onukiabe84422016-04-07 09:41:19 -07001039 *
1040 * @param shortcut The target shortcut.
1041 * @param sourceBounds The Rect containing the source bounds of the clicked icon.
1042 * @param startActivityOptions Options to pass to startActivity.
Makoto Onuki02f338e2016-07-29 09:40:40 -07001043 * @throws IllegalStateException when the user is locked, or when the {@code user} user
1044 * is locked or not running.
Makoto Onuki83f6d2d2016-07-11 14:30:19 -07001045 *
1046 * @throws android.content.ActivityNotFoundException failed to start shortcut. (e.g.
1047 * the shortcut no longer exists, is disabled, the intent receiver activity doesn't exist, etc)
Makoto Onukiabe84422016-04-07 09:41:19 -07001048 */
Makoto Onukid6880792016-06-29 13:37:43 -07001049 public void startShortcut(@NonNull ShortcutInfo shortcut,
Makoto Onukiabe84422016-04-07 09:41:19 -07001050 @Nullable Rect sourceBounds, @Nullable Bundle startActivityOptions) {
Makoto Onukid6880792016-06-29 13:37:43 -07001051 startShortcut(shortcut.getPackage(), shortcut.getId(),
Makoto Onukiabe84422016-04-07 09:41:19 -07001052 sourceBounds, startActivityOptions,
1053 shortcut.getUserId());
1054 }
1055
Makoto Onukid6880792016-06-29 13:37:43 -07001056 private void startShortcut(@NonNull String packageName, @NonNull String shortcutId,
Makoto Onukiabe84422016-04-07 09:41:19 -07001057 @Nullable Rect sourceBounds, @Nullable Bundle startActivityOptions,
1058 int userId) {
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001059 try {
Makoto Onuki83f6d2d2016-07-11 14:30:19 -07001060 final boolean success =
1061 mService.startShortcut(mContext.getPackageName(), packageName, shortcutId,
Makoto Onukiabe84422016-04-07 09:41:19 -07001062 sourceBounds, startActivityOptions, userId);
Makoto Onuki83f6d2d2016-07-11 14:30:19 -07001063 if (!success) {
1064 throw new ActivityNotFoundException("Shortcut could not be started");
1065 }
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001066 } catch (RemoteException e) {
1067 throw e.rethrowFromSystemServer();
1068 }
1069 }
Kenny Guy53fa4ec2014-04-29 14:24:18 +01001070
1071 /**
Kenny Guy10a574f2014-08-26 16:17:58 +01001072 * Registers a callback for changes to packages in current and managed profiles.
Kenny Guyc01545372014-06-16 14:17:26 +01001073 *
Kenny Guy10a574f2014-08-26 16:17:58 +01001074 * @param callback The callback to register.
Kenny Guyc01545372014-06-16 14:17:26 +01001075 */
Kenny Guy10a574f2014-08-26 16:17:58 +01001076 public void registerCallback(Callback callback) {
1077 registerCallback(callback, null);
Kenny Guyb42c89b2014-07-28 19:20:07 +01001078 }
1079
1080 /**
Kenny Guy10a574f2014-08-26 16:17:58 +01001081 * Registers a callback for changes to packages in current and managed profiles.
Kenny Guyb42c89b2014-07-28 19:20:07 +01001082 *
Kenny Guy10a574f2014-08-26 16:17:58 +01001083 * @param callback The callback to register.
Kenny Guyb42c89b2014-07-28 19:20:07 +01001084 * @param handler that should be used to post callbacks on, may be null.
1085 */
Kenny Guy10a574f2014-08-26 16:17:58 +01001086 public void registerCallback(Callback callback, Handler handler) {
Kenny Guyc01545372014-06-16 14:17:26 +01001087 synchronized (this) {
Kenny Guy172a2162015-06-19 17:21:28 +01001088 if (callback != null && findCallbackLocked(callback) < 0) {
Kenny Guyb42c89b2014-07-28 19:20:07 +01001089 boolean addedFirstCallback = mCallbacks.size() == 0;
1090 addCallbackLocked(callback, handler);
1091 if (addedFirstCallback) {
Kenny Guyc01545372014-06-16 14:17:26 +01001092 try {
Makoto Onuki4dbe0de2016-03-14 17:31:49 -07001093 mService.addOnAppsChangedListener(mContext.getPackageName(),
1094 mAppsChangedListener);
Kenny Guyc01545372014-06-16 14:17:26 +01001095 } catch (RemoteException re) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001096 throw re.rethrowFromSystemServer();
Kenny Guyc01545372014-06-16 14:17:26 +01001097 }
1098 }
1099 }
1100 }
1101 }
1102
1103 /**
Kenny Guy10a574f2014-08-26 16:17:58 +01001104 * Unregisters a callback that was previously registered.
Kenny Guyc01545372014-06-16 14:17:26 +01001105 *
Kenny Guy10a574f2014-08-26 16:17:58 +01001106 * @param callback The callback to unregister.
1107 * @see #registerCallback(Callback)
Kenny Guyc01545372014-06-16 14:17:26 +01001108 */
Kenny Guy10a574f2014-08-26 16:17:58 +01001109 public void unregisterCallback(Callback callback) {
Kenny Guyc01545372014-06-16 14:17:26 +01001110 synchronized (this) {
Kenny Guyb42c89b2014-07-28 19:20:07 +01001111 removeCallbackLocked(callback);
Kenny Guy44b6dee2014-07-10 18:10:14 +01001112 if (mCallbacks.size() == 0) {
Amith Yamasanie781c812014-05-28 15:28:18 -07001113 try {
1114 mService.removeOnAppsChangedListener(mAppsChangedListener);
1115 } catch (RemoteException re) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001116 throw re.rethrowFromSystemServer();
Amith Yamasanie781c812014-05-28 15:28:18 -07001117 }
Amith Yamasani4f582632014-02-19 14:31:52 -08001118 }
1119 }
1120 }
1121
Kenny Guy172a2162015-06-19 17:21:28 +01001122 /** @return position in mCallbacks for callback or -1 if not present. */
1123 private int findCallbackLocked(Callback callback) {
Kenny Guyb42c89b2014-07-28 19:20:07 +01001124 if (callback == null) {
1125 throw new IllegalArgumentException("Callback cannot be null");
1126 }
1127 final int size = mCallbacks.size();
1128 for (int i = 0; i < size; ++i) {
1129 if (mCallbacks.get(i).mCallback == callback) {
Kenny Guy172a2162015-06-19 17:21:28 +01001130 return i;
Kenny Guyb42c89b2014-07-28 19:20:07 +01001131 }
1132 }
Kenny Guy172a2162015-06-19 17:21:28 +01001133 return -1;
1134 }
1135
1136 private void removeCallbackLocked(Callback callback) {
1137 int pos = findCallbackLocked(callback);
1138 if (pos >= 0) {
1139 mCallbacks.remove(pos);
1140 }
Kenny Guyb42c89b2014-07-28 19:20:07 +01001141 }
1142
Kenny Guyf939dba2014-08-15 15:32:34 +01001143 private void addCallbackLocked(Callback callback, Handler handler) {
Kenny Guyb42c89b2014-07-28 19:20:07 +01001144 // Remove if already present.
1145 removeCallbackLocked(callback);
1146 if (handler == null) {
1147 handler = new Handler();
1148 }
1149 CallbackMessageHandler toAdd = new CallbackMessageHandler(handler.getLooper(), callback);
1150 mCallbacks.add(toAdd);
1151 }
1152
Amith Yamasani4f582632014-02-19 14:31:52 -08001153 private IOnAppsChangedListener.Stub mAppsChangedListener = new IOnAppsChangedListener.Stub() {
1154
1155 @Override
Kenny Guyb42c89b2014-07-28 19:20:07 +01001156 public void onPackageRemoved(UserHandle user, String packageName)
1157 throws RemoteException {
Amith Yamasani4f582632014-02-19 14:31:52 -08001158 if (DEBUG) {
1159 Log.d(TAG, "onPackageRemoved " + user.getIdentifier() + "," + packageName);
1160 }
1161 synchronized (LauncherApps.this) {
Kenny Guyb42c89b2014-07-28 19:20:07 +01001162 for (CallbackMessageHandler callback : mCallbacks) {
1163 callback.postOnPackageRemoved(packageName, user);
Kenny Guyc01545372014-06-16 14:17:26 +01001164 }
Amith Yamasani4f582632014-02-19 14:31:52 -08001165 }
1166 }
1167
1168 @Override
1169 public void onPackageChanged(UserHandle user, String packageName) throws RemoteException {
1170 if (DEBUG) {
1171 Log.d(TAG, "onPackageChanged " + user.getIdentifier() + "," + packageName);
1172 }
1173 synchronized (LauncherApps.this) {
Kenny Guyb42c89b2014-07-28 19:20:07 +01001174 for (CallbackMessageHandler callback : mCallbacks) {
1175 callback.postOnPackageChanged(packageName, user);
Kenny Guyc01545372014-06-16 14:17:26 +01001176 }
Amith Yamasani4f582632014-02-19 14:31:52 -08001177 }
1178 }
1179
1180 @Override
1181 public void onPackageAdded(UserHandle user, String packageName) throws RemoteException {
1182 if (DEBUG) {
1183 Log.d(TAG, "onPackageAdded " + user.getIdentifier() + "," + packageName);
1184 }
1185 synchronized (LauncherApps.this) {
Kenny Guyb42c89b2014-07-28 19:20:07 +01001186 for (CallbackMessageHandler callback : mCallbacks) {
1187 callback.postOnPackageAdded(packageName, user);
Kenny Guyc01545372014-06-16 14:17:26 +01001188 }
Amith Yamasani4f582632014-02-19 14:31:52 -08001189 }
1190 }
1191
1192 @Override
1193 public void onPackagesAvailable(UserHandle user, String[] packageNames, boolean replacing)
1194 throws RemoteException {
1195 if (DEBUG) {
1196 Log.d(TAG, "onPackagesAvailable " + user.getIdentifier() + "," + packageNames);
1197 }
1198 synchronized (LauncherApps.this) {
Kenny Guyb42c89b2014-07-28 19:20:07 +01001199 for (CallbackMessageHandler callback : mCallbacks) {
1200 callback.postOnPackagesAvailable(packageNames, user, replacing);
Kenny Guyc01545372014-06-16 14:17:26 +01001201 }
Amith Yamasani4f582632014-02-19 14:31:52 -08001202 }
1203 }
1204
1205 @Override
1206 public void onPackagesUnavailable(UserHandle user, String[] packageNames, boolean replacing)
1207 throws RemoteException {
1208 if (DEBUG) {
1209 Log.d(TAG, "onPackagesUnavailable " + user.getIdentifier() + "," + packageNames);
1210 }
1211 synchronized (LauncherApps.this) {
Kenny Guyb42c89b2014-07-28 19:20:07 +01001212 for (CallbackMessageHandler callback : mCallbacks) {
1213 callback.postOnPackagesUnavailable(packageNames, user, replacing);
Kenny Guyc01545372014-06-16 14:17:26 +01001214 }
Kenny Guy77242752016-01-15 13:29:06 +00001215 }
1216 }
1217
1218 @Override
Suprabh Shukla19b41f32018-03-26 22:35:13 -07001219 public void onPackagesSuspended(UserHandle user, String[] packageNames,
1220 Bundle launcherExtras)
Kenny Guy77242752016-01-15 13:29:06 +00001221 throws RemoteException {
1222 if (DEBUG) {
1223 Log.d(TAG, "onPackagesSuspended " + user.getIdentifier() + "," + packageNames);
1224 }
1225 synchronized (LauncherApps.this) {
1226 for (CallbackMessageHandler callback : mCallbacks) {
Suprabh Shukla19b41f32018-03-26 22:35:13 -07001227 callback.postOnPackagesSuspended(packageNames, launcherExtras, user);
Kenny Guy77242752016-01-15 13:29:06 +00001228 }
1229 }
1230 }
1231
1232 @Override
1233 public void onPackagesUnsuspended(UserHandle user, String[] packageNames)
1234 throws RemoteException {
1235 if (DEBUG) {
1236 Log.d(TAG, "onPackagesUnsuspended " + user.getIdentifier() + "," + packageNames);
1237 }
1238 synchronized (LauncherApps.this) {
1239 for (CallbackMessageHandler callback : mCallbacks) {
1240 callback.postOnPackagesUnsuspended(packageNames, user);
1241 }
1242 }
Amith Yamasani4f582632014-02-19 14:31:52 -08001243 }
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001244
1245 @Override
1246 public void onShortcutChanged(UserHandle user, String packageName,
1247 ParceledListSlice shortcuts) {
1248 if (DEBUG) {
1249 Log.d(TAG, "onShortcutChanged " + user.getIdentifier() + "," + packageName);
1250 }
1251 final List<ShortcutInfo> list = shortcuts.getList();
1252 synchronized (LauncherApps.this) {
1253 for (CallbackMessageHandler callback : mCallbacks) {
1254 callback.postOnShortcutChanged(packageName, user, list);
1255 }
1256 }
1257 }
Amith Yamasani4f582632014-02-19 14:31:52 -08001258 };
Kenny Guyb42c89b2014-07-28 19:20:07 +01001259
1260 private static class CallbackMessageHandler extends Handler {
1261 private static final int MSG_ADDED = 1;
1262 private static final int MSG_REMOVED = 2;
1263 private static final int MSG_CHANGED = 3;
1264 private static final int MSG_AVAILABLE = 4;
1265 private static final int MSG_UNAVAILABLE = 5;
Kenny Guy77242752016-01-15 13:29:06 +00001266 private static final int MSG_SUSPENDED = 6;
1267 private static final int MSG_UNSUSPENDED = 7;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001268 private static final int MSG_SHORTCUT_CHANGED = 8;
Kenny Guyb42c89b2014-07-28 19:20:07 +01001269
Kenny Guyf939dba2014-08-15 15:32:34 +01001270 private LauncherApps.Callback mCallback;
Kenny Guyb42c89b2014-07-28 19:20:07 +01001271
1272 private static class CallbackInfo {
1273 String[] packageNames;
1274 String packageName;
Suprabh Shukla19b41f32018-03-26 22:35:13 -07001275 Bundle launcherExtras;
Kenny Guyb42c89b2014-07-28 19:20:07 +01001276 boolean replacing;
1277 UserHandle user;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001278 List<ShortcutInfo> shortcuts;
Kenny Guyb42c89b2014-07-28 19:20:07 +01001279 }
1280
Kenny Guyf939dba2014-08-15 15:32:34 +01001281 public CallbackMessageHandler(Looper looper, LauncherApps.Callback callback) {
Kenny Guyb42c89b2014-07-28 19:20:07 +01001282 super(looper, null, true);
1283 mCallback = callback;
1284 }
1285
1286 @Override
1287 public void handleMessage(Message msg) {
1288 if (mCallback == null || !(msg.obj instanceof CallbackInfo)) {
1289 return;
1290 }
1291 CallbackInfo info = (CallbackInfo) msg.obj;
1292 switch (msg.what) {
1293 case MSG_ADDED:
1294 mCallback.onPackageAdded(info.packageName, info.user);
1295 break;
1296 case MSG_REMOVED:
1297 mCallback.onPackageRemoved(info.packageName, info.user);
1298 break;
1299 case MSG_CHANGED:
1300 mCallback.onPackageChanged(info.packageName, info.user);
1301 break;
1302 case MSG_AVAILABLE:
1303 mCallback.onPackagesAvailable(info.packageNames, info.user, info.replacing);
1304 break;
1305 case MSG_UNAVAILABLE:
1306 mCallback.onPackagesUnavailable(info.packageNames, info.user, info.replacing);
1307 break;
Kenny Guy77242752016-01-15 13:29:06 +00001308 case MSG_SUSPENDED:
Suprabh Shukla96212bc2018-04-10 15:04:51 -07001309 mCallback.onPackagesSuspended(info.packageNames, info.user, info.launcherExtras
1310 );
Kenny Guy77242752016-01-15 13:29:06 +00001311 break;
1312 case MSG_UNSUSPENDED:
1313 mCallback.onPackagesUnsuspended(info.packageNames, info.user);
1314 break;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001315 case MSG_SHORTCUT_CHANGED:
1316 mCallback.onShortcutsChanged(info.packageName, info.shortcuts, info.user);
1317 break;
Kenny Guyb42c89b2014-07-28 19:20:07 +01001318 }
1319 }
1320
1321 public void postOnPackageAdded(String packageName, UserHandle user) {
1322 CallbackInfo info = new CallbackInfo();
1323 info.packageName = packageName;
1324 info.user = user;
1325 obtainMessage(MSG_ADDED, info).sendToTarget();
1326 }
1327
1328 public void postOnPackageRemoved(String packageName, UserHandle user) {
1329 CallbackInfo info = new CallbackInfo();
1330 info.packageName = packageName;
1331 info.user = user;
1332 obtainMessage(MSG_REMOVED, info).sendToTarget();
1333 }
1334
1335 public void postOnPackageChanged(String packageName, UserHandle user) {
1336 CallbackInfo info = new CallbackInfo();
1337 info.packageName = packageName;
1338 info.user = user;
1339 obtainMessage(MSG_CHANGED, info).sendToTarget();
1340 }
1341
1342 public void postOnPackagesAvailable(String[] packageNames, UserHandle user,
1343 boolean replacing) {
1344 CallbackInfo info = new CallbackInfo();
1345 info.packageNames = packageNames;
1346 info.replacing = replacing;
1347 info.user = user;
1348 obtainMessage(MSG_AVAILABLE, info).sendToTarget();
1349 }
1350
1351 public void postOnPackagesUnavailable(String[] packageNames, UserHandle user,
1352 boolean replacing) {
1353 CallbackInfo info = new CallbackInfo();
1354 info.packageNames = packageNames;
1355 info.replacing = replacing;
1356 info.user = user;
1357 obtainMessage(MSG_UNAVAILABLE, info).sendToTarget();
1358 }
Kenny Guy77242752016-01-15 13:29:06 +00001359
Suprabh Shukla19b41f32018-03-26 22:35:13 -07001360 public void postOnPackagesSuspended(String[] packageNames, Bundle launcherExtras,
1361 UserHandle user) {
Kenny Guy77242752016-01-15 13:29:06 +00001362 CallbackInfo info = new CallbackInfo();
1363 info.packageNames = packageNames;
1364 info.user = user;
Suprabh Shukla19b41f32018-03-26 22:35:13 -07001365 info.launcherExtras = launcherExtras;
Kenny Guy77242752016-01-15 13:29:06 +00001366 obtainMessage(MSG_SUSPENDED, info).sendToTarget();
1367 }
1368
1369 public void postOnPackagesUnsuspended(String[] packageNames, UserHandle user) {
1370 CallbackInfo info = new CallbackInfo();
1371 info.packageNames = packageNames;
1372 info.user = user;
1373 obtainMessage(MSG_UNSUSPENDED, info).sendToTarget();
1374 }
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001375
1376 public void postOnShortcutChanged(String packageName, UserHandle user,
1377 List<ShortcutInfo> shortcuts) {
1378 CallbackInfo info = new CallbackInfo();
1379 info.packageName = packageName;
1380 info.user = user;
1381 info.shortcuts = shortcuts;
1382 obtainMessage(MSG_SHORTCUT_CHANGED, info).sendToTarget();
1383 }
Kenny Guyb42c89b2014-07-28 19:20:07 +01001384 }
Makoto Onuki2d895c32016-12-02 15:48:40 -08001385
1386 /**
1387 * A helper method to extract a {@link PinItemRequest} set to
1388 * the {@link #EXTRA_PIN_ITEM_REQUEST} extra.
1389 */
1390 public PinItemRequest getPinItemRequest(Intent intent) {
1391 return intent.getParcelableExtra(EXTRA_PIN_ITEM_REQUEST);
1392 }
1393
1394 /**
Sunny Goyal7f7372a2017-01-24 11:53:54 -08001395 * Represents a "pin shortcut" or a "pin appwidget" request made by an app, which is sent with
1396 * an {@link #ACTION_CONFIRM_PIN_SHORTCUT} or {@link #ACTION_CONFIRM_PIN_APPWIDGET} intent
1397 * respectively to the default launcher app.
Makoto Onuki2d895c32016-12-02 15:48:40 -08001398 *
Makoto Onukia37ac3d2017-04-14 12:33:10 -07001399 * <h3>Request of the {@link #REQUEST_TYPE_SHORTCUT} type.
Makoto Onuki0c280712017-01-19 15:14:27 -08001400 *
Makoto Onukia37ac3d2017-04-14 12:33:10 -07001401 * <p>A {@link #REQUEST_TYPE_SHORTCUT} request represents a request to pin a
1402 * {@link ShortcutInfo}. If the launcher accepts a request, call {@link #accept()},
1403 * or {@link #accept(Bundle)} with a null or empty Bundle. No options are defined for
1404 * pin-shortcuts requests.
1405 *
1406 * <p>{@link #getShortcutInfo()} always returns a non-null {@link ShortcutInfo} for this type.
1407 *
1408 * <p>The launcher may receive a request with a {@link ShortcutInfo} that is already pinned, in
1409 * which case {@link ShortcutInfo#isPinned()} returns true. This means the user wants to create
1410 * another pinned shortcut for a shortcut that's already pinned. If the launcher accepts it,
1411 * {@link #accept()} must still be called even though the shortcut is already pinned, and
1412 * create a new pinned shortcut icon for it.
1413 *
1414 * <p>See also {@link ShortcutManager} for more details.
1415 *
1416 * <h3>Request of the {@link #REQUEST_TYPE_APPWIDGET} type.
1417 *
1418 * <p>A {@link #REQUEST_TYPE_SHORTCUT} request represents a request to pin a
1419 * an AppWidget. If the launcher accepts a request, call {@link #accept(Bundle)} with
1420 * the appwidget integer ID set to the
1421 * {@link android.appwidget.AppWidgetManager#EXTRA_APPWIDGET_ID} extra.
1422 *
1423 * <p>{@link #getAppWidgetProviderInfo(Context)} always returns a non-null
1424 * {@link AppWidgetProviderInfo} for this type.
1425 *
1426 * <p>See also {@link AppWidgetManager} for more details.
Sunny Goyal7f7372a2017-01-24 11:53:54 -08001427 *
Makoto Onuki2d895c32016-12-02 15:48:40 -08001428 * @see #EXTRA_PIN_ITEM_REQUEST
1429 * @see #getPinItemRequest(Intent)
1430 */
1431 public static final class PinItemRequest implements Parcelable {
1432
1433 /** This is a request to pin shortcut. */
1434 public static final int REQUEST_TYPE_SHORTCUT = 1;
1435
Sunny Goyal87a563e2017-01-01 19:42:45 -08001436 /** This is a request to pin app widget. */
1437 public static final int REQUEST_TYPE_APPWIDGET = 2;
1438
Makoto Onukif5663b12017-01-09 14:09:56 -08001439 /** @hide */
Jeff Sharkeyce8db992017-12-13 20:05:05 -07001440 @IntDef(prefix = { "REQUEST_TYPE_" }, value = {
1441 REQUEST_TYPE_SHORTCUT,
1442 REQUEST_TYPE_APPWIDGET
1443 })
Makoto Onuki2d895c32016-12-02 15:48:40 -08001444 @Retention(RetentionPolicy.SOURCE)
1445 public @interface RequestType {}
1446
1447 private final int mRequestType;
Makoto Onuki2d895c32016-12-02 15:48:40 -08001448 private final IPinItemRequest mInner;
1449
1450 /**
1451 * @hide
1452 */
Makoto Onuki8abba3a2017-02-24 11:34:54 -08001453 public PinItemRequest(IPinItemRequest inner, int type) {
Sunny Goyal87a563e2017-01-01 19:42:45 -08001454 mInner = inner;
Makoto Onuki8abba3a2017-02-24 11:34:54 -08001455 mRequestType = type;
Makoto Onuki2d895c32016-12-02 15:48:40 -08001456 }
1457
1458 /**
Makoto Onukia37ac3d2017-04-14 12:33:10 -07001459 * Represents the type of a request, which is one of the {@code REQUEST_TYPE_} constants.
1460 *
1461 * @return one of the {@code REQUEST_TYPE_} constants.
Makoto Onuki2d895c32016-12-02 15:48:40 -08001462 */
1463 @RequestType
1464 public int getRequestType() {
1465 return mRequestType;
1466 }
1467
1468 /**
Makoto Onukia37ac3d2017-04-14 12:33:10 -07001469 * {@link ShortcutInfo} sent by the requesting app.
1470 * Always non-null for a {@link #REQUEST_TYPE_SHORTCUT} request, and always null for a
1471 * different request type.
1472 *
1473 * @return requested {@link ShortcutInfo} when a request is of the
1474 * {@link #REQUEST_TYPE_SHORTCUT} type. Null otherwise.
Makoto Onuki2d895c32016-12-02 15:48:40 -08001475 */
1476 @Nullable
1477 public ShortcutInfo getShortcutInfo() {
Makoto Onuki8abba3a2017-02-24 11:34:54 -08001478 try {
1479 return mInner.getShortcutInfo();
1480 } catch (RemoteException e) {
1481 throw e.rethrowAsRuntimeException();
1482 }
Makoto Onuki2d895c32016-12-02 15:48:40 -08001483 }
1484
1485 /**
Makoto Onukia37ac3d2017-04-14 12:33:10 -07001486 * {@link AppWidgetProviderInfo} sent by the requesting app.
1487 * Always non-null for a {@link #REQUEST_TYPE_APPWIDGET} request, and always null for a
1488 * different request type.
1489 *
Sunny Goyale7712ad2018-03-08 11:23:06 -08001490 * <p>Launcher should not show any configuration activity associated with the provider, and
1491 * assume that the widget is already fully configured. Upon accepting the widget, it should
1492 * pass the widgetId in {@link #accept(Bundle)}.
1493 *
Makoto Onukia37ac3d2017-04-14 12:33:10 -07001494 * @return requested {@link AppWidgetProviderInfo} when a request is of the
1495 * {@link #REQUEST_TYPE_APPWIDGET} type. Null otherwise.
Sunny Goyal87a563e2017-01-01 19:42:45 -08001496 */
1497 @Nullable
Sunny Goyal970d4b42017-01-19 15:07:36 -08001498 public AppWidgetProviderInfo getAppWidgetProviderInfo(Context context) {
Makoto Onuki8abba3a2017-02-24 11:34:54 -08001499 try {
1500 final AppWidgetProviderInfo info = mInner.getAppWidgetProviderInfo();
1501 if (info == null) {
1502 return null;
1503 }
Sunny Goyal970d4b42017-01-19 15:07:36 -08001504 info.updateDimensions(context.getResources().getDisplayMetrics());
1505 return info;
Makoto Onuki8abba3a2017-02-24 11:34:54 -08001506 } catch (RemoteException e) {
1507 throw e.rethrowAsRuntimeException();
Sunny Goyal970d4b42017-01-19 15:07:36 -08001508 }
Sunny Goyal87a563e2017-01-01 19:42:45 -08001509 }
1510
1511 /**
Sunny Goyal4ad6b572017-02-28 11:11:51 -08001512 * Any extras sent by the requesting app.
Makoto Onukia37ac3d2017-04-14 12:33:10 -07001513 *
1514 * @return For a shortcut request, this method always return null. For an AppWidget
1515 * request, this method returns the extras passed to the
1516 * {@link android.appwidget.AppWidgetManager#requestPinAppWidget(
1517 * ComponentName, Bundle, PendingIntent)} API. See {@link AppWidgetManager} for details.
Sunny Goyal4ad6b572017-02-28 11:11:51 -08001518 */
1519 @Nullable
1520 public Bundle getExtras() {
1521 try {
1522 return mInner.getExtras();
1523 } catch (RemoteException e) {
1524 throw e.rethrowAsRuntimeException();
1525 }
1526 }
1527
1528 /**
Makoto Onukia37ac3d2017-04-14 12:33:10 -07001529 * Return whether a request is still valid.
1530 *
1531 * @return {@code TRUE} if a request is valid and {@link #accept(Bundle)} may be called.
Makoto Onuki2d895c32016-12-02 15:48:40 -08001532 */
1533 public boolean isValid() {
1534 try {
1535 return mInner.isValid();
1536 } catch (RemoteException e) {
1537 return false;
1538 }
1539 }
1540
1541 /**
1542 * Called by the receiving launcher app when the user accepts the request.
Makoto Onukia37ac3d2017-04-14 12:33:10 -07001543 *
1544 * @param options must be set for a {@link #REQUEST_TYPE_APPWIDGET} request.
1545 *
1546 * @return {@code TRUE} if the shortcut or the AppWidget has actually been pinned.
1547 * {@code FALSE} if the item hasn't been pinned, for example, because the request had
1548 * already been canceled, in which case the launcher must not pin the requested item.
Makoto Onuki2d895c32016-12-02 15:48:40 -08001549 */
1550 public boolean accept(@Nullable Bundle options) {
1551 try {
1552 return mInner.accept(options);
1553 } catch (RemoteException e) {
1554 throw e.rethrowFromSystemServer();
1555 }
1556 }
1557
1558 /**
Makoto Onukia37ac3d2017-04-14 12:33:10 -07001559 * Called by the receiving launcher app when the user accepts the request, with no options.
1560 *
1561 * @return {@code TRUE} if the shortcut or the AppWidget has actually been pinned.
1562 * {@code FALSE} if the item hasn't been pinned, for example, because the request had
1563 * already been canceled, in which case the launcher must not pin the requested item.
Makoto Onuki2d895c32016-12-02 15:48:40 -08001564 */
1565 public boolean accept() {
1566 return accept(/* options= */ null);
1567 }
1568
1569 private PinItemRequest(Parcel source) {
1570 final ClassLoader cl = getClass().getClassLoader();
1571
1572 mRequestType = source.readInt();
Makoto Onuki2d895c32016-12-02 15:48:40 -08001573 mInner = IPinItemRequest.Stub.asInterface(source.readStrongBinder());
1574 }
1575
1576 @Override
1577 public void writeToParcel(Parcel dest, int flags) {
1578 dest.writeInt(mRequestType);
Makoto Onuki2d895c32016-12-02 15:48:40 -08001579 dest.writeStrongBinder(mInner.asBinder());
1580 }
1581
1582 public static final Creator<PinItemRequest> CREATOR =
1583 new Creator<PinItemRequest>() {
1584 public PinItemRequest createFromParcel(Parcel source) {
1585 return new PinItemRequest(source);
1586 }
1587 public PinItemRequest[] newArray(int size) {
1588 return new PinItemRequest[size];
1589 }
1590 };
1591
1592 @Override
1593 public int describeContents() {
1594 return 0;
1595 }
1596 }
Amith Yamasani4f582632014-02-19 14:31:52 -08001597}