blob: 4e4897f59ad383064ecab95391291adb7e89020b [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
arangelov08abd0f2020-01-24 17:09:56 +000019import static android.Manifest.permission;
Mehdi Alizadehb754b7a2020-02-13 20:54:43 -080020
Jon Miranda2b340a22019-01-25 14:03:49 -080021import android.annotation.CallbackExecutor;
Makoto Onuki6f7362d92016-03-04 13:39:41 -080022import android.annotation.IntDef;
23import android.annotation.NonNull;
24import android.annotation.Nullable;
Mehdi Alizadeh0de8c292020-01-21 17:27:26 -080025import android.annotation.RequiresPermission;
Makoto Onuki2d895c32016-12-02 15:48:40 -080026import android.annotation.SdkConstant;
27import android.annotation.SdkConstant.SdkConstantType;
Sunny Goyalbeee1972019-03-29 11:38:16 -070028import android.annotation.SystemApi;
Makoto Onukib1588c02017-10-12 15:11:45 -070029import android.annotation.SystemService;
Makoto Onuki5ba0d3e2016-04-11 14:03:46 -070030import android.annotation.TestApi;
Makoto Onukia37ac3d2017-04-14 12:33:10 -070031import android.app.PendingIntent;
32import android.appwidget.AppWidgetManager;
Sunny Goyal87a563e2017-01-01 19:42:45 -080033import android.appwidget.AppWidgetProviderInfo;
Artur Satayeve23a0eb2019-12-10 17:47:52 +000034import android.compat.annotation.UnsupportedAppUsage;
Makoto Onuki83f6d2d2016-07-11 14:30:19 -070035import android.content.ActivityNotFoundException;
Amith Yamasani4f582632014-02-19 14:31:52 -080036import android.content.ComponentName;
37import android.content.Context;
38import android.content.Intent;
Sunny Goyala6be88a2017-01-12 16:27:58 -080039import android.content.IntentSender;
Mehdi Alizadehae808ff2020-01-21 13:39:53 -080040import android.content.LocusId;
Jon Miranda2b340a22019-01-25 14:03:49 -080041import android.content.pm.PackageInstaller.SessionCallback;
42import android.content.pm.PackageInstaller.SessionCallbackDelegate;
43import android.content.pm.PackageInstaller.SessionInfo;
Kenny Guy77242752016-01-15 13:29:06 +000044import android.content.pm.PackageManager.ApplicationInfoFlags;
Makoto Onuki04b9aab2016-05-23 17:13:30 -070045import android.content.pm.PackageManager.NameNotFoundException;
46import android.content.res.Resources;
47import android.graphics.Bitmap;
48import android.graphics.BitmapFactory;
Amith Yamasani4f582632014-02-19 14:31:52 -080049import android.graphics.Rect;
Makoto Onukib1588c02017-10-12 15:11:45 -070050import android.graphics.drawable.AdaptiveIconDrawable;
Makoto Onuki04b9aab2016-05-23 17:13:30 -070051import android.graphics.drawable.BitmapDrawable;
Makoto Onuki20c95f82016-05-11 16:51:01 -070052import android.graphics.drawable.Drawable;
Makoto Onuki2d895c32016-12-02 15:48:40 -080053import android.graphics.drawable.Icon;
Mathew Inwood8c854f82018-09-14 12:35:36 +010054import android.os.Build;
Amith Yamasani4f582632014-02-19 14:31:52 -080055import android.os.Bundle;
Kenny Guyb42c89b2014-07-28 19:20:07 +010056import android.os.Handler;
57import android.os.Looper;
58import android.os.Message;
Makoto Onuki2d895c32016-12-02 15:48:40 -080059import android.os.Parcel;
Makoto Onuki6f7362d92016-03-04 13:39:41 -080060import android.os.ParcelFileDescriptor;
Makoto Onuki2d895c32016-12-02 15:48:40 -080061import android.os.Parcelable;
Amith Yamasani4f582632014-02-19 14:31:52 -080062import android.os.RemoteException;
Makoto Onuki5ba0d3e2016-04-11 14:03:46 -070063import android.os.ServiceManager;
Amith Yamasani4f582632014-02-19 14:31:52 -080064import android.os.UserHandle;
Amith Yamasanie781c812014-05-28 15:28:18 -070065import android.os.UserManager;
Makoto Onuki04b9aab2016-05-23 17:13:30 -070066import android.util.DisplayMetrics;
Amith Yamasani4f582632014-02-19 14:31:52 -080067import android.util.Log;
Mehdi Alizadeh9f680192020-01-16 18:09:24 -080068import android.util.Pair;
69
70import com.android.internal.util.function.pooled.PooledLambda;
Amith Yamasani4f582632014-02-19 14:31:52 -080071
Makoto Onuki04b9aab2016-05-23 17:13:30 -070072import java.io.IOException;
Makoto Onuki6f7362d92016-03-04 13:39:41 -080073import java.lang.annotation.Retention;
74import java.lang.annotation.RetentionPolicy;
Mehdi Alizadeh9f680192020-01-16 18:09:24 -080075import java.lang.ref.WeakReference;
Amith Yamasani4f582632014-02-19 14:31:52 -080076import java.util.ArrayList;
Makoto Onukib6d35232016-04-04 15:57:17 -070077import java.util.Arrays;
Amith Yamasani4f582632014-02-19 14:31:52 -080078import java.util.Collections;
Mehdi Alizadeh9f680192020-01-16 18:09:24 -080079import java.util.HashMap;
Jon Miranda2b340a22019-01-25 14:03:49 -080080import java.util.Iterator;
Amith Yamasani4f582632014-02-19 14:31:52 -080081import java.util.List;
Mehdi Alizadeh9f680192020-01-16 18:09:24 -080082import java.util.Map;
Daulet Zhanguzina2044e12019-12-30 16:34:59 +000083import java.util.Objects;
Jon Miranda2b340a22019-01-25 14:03:49 -080084import java.util.concurrent.Executor;
Amith Yamasani4f582632014-02-19 14:31:52 -080085
86/**
87 * Class for retrieving a list of launchable activities for the current user and any associated
Makoto Onukiaecbd032017-01-19 12:11:11 -080088 * managed profiles that are visible to the current user, which can be retrieved with
89 * {@link #getProfiles}. This is mainly for use by launchers.
90 *
91 * Apps can be queried for each user profile.
Amith Yamasani4f582632014-02-19 14:31:52 -080092 * Since the PackageManager will not deliver package broadcasts for other profiles, you can register
93 * for package changes here.
Amith Yamasanie781c812014-05-28 15:28:18 -070094 * <p>
95 * To watch for managed profiles being added or removed, register for the following broadcasts:
96 * {@link Intent#ACTION_MANAGED_PROFILE_ADDED} and {@link Intent#ACTION_MANAGED_PROFILE_REMOVED}.
97 * <p>
Makoto Onukiaecbd032017-01-19 12:11:11 -080098 * Note as of Android O, apps on a managed profile are no longer allowed to access apps on the
99 * main profile. Apps can only access profiles returned by {@link #getProfiles()}.
Amith Yamasani4f582632014-02-19 14:31:52 -0800100 */
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -0600101@SystemService(Context.LAUNCHER_APPS_SERVICE)
Amith Yamasani4f582632014-02-19 14:31:52 -0800102public class LauncherApps {
103
104 static final String TAG = "LauncherApps";
105 static final boolean DEBUG = false;
106
Makoto Onuki2d895c32016-12-02 15:48:40 -0800107 /**
108 * Activity Action: For the default launcher to show the confirmation dialog to create
109 * a pinned shortcut.
110 *
111 * <p>See the {@link ShortcutManager} javadoc for 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)
Sunny Goyal7f7372a2017-01-24 11:53:54 -0800121 public static final String ACTION_CONFIRM_PIN_SHORTCUT =
122 "android.content.pm.action.CONFIRM_PIN_SHORTCUT";
Makoto Onuki2d895c32016-12-02 15:48:40 -0800123
124 /**
Sunny Goyal7f7372a2017-01-24 11:53:54 -0800125 * Activity Action: For the default launcher to show the confirmation dialog to create
126 * a pinned app widget.
127 *
128 * <p>See the {@link android.appwidget.AppWidgetManager#requestPinAppWidget} javadoc for
129 * details.
130 *
131 * <p>
132 * Use {@link #getPinItemRequest(Intent)} to get a {@link PinItemRequest} object,
133 * and call {@link PinItemRequest#accept(Bundle)}
134 * if the user accepts. If the user doesn't accept, no further action is required.
135 *
136 * @see #EXTRA_PIN_ITEM_REQUEST
137 */
138 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
139 public static final String ACTION_CONFIRM_PIN_APPWIDGET =
140 "android.content.pm.action.CONFIRM_PIN_APPWIDGET";
141
142 /**
143 * An extra for {@link #ACTION_CONFIRM_PIN_SHORTCUT} &amp; {@link #ACTION_CONFIRM_PIN_APPWIDGET}
144 * containing a {@link PinItemRequest} of appropriate type asked to pin.
Makoto Onuki2d895c32016-12-02 15:48:40 -0800145 *
146 * <p>A helper function {@link #getPinItemRequest(Intent)} can be used
147 * instead of using this constant directly.
148 *
Sunny Goyal7f7372a2017-01-24 11:53:54 -0800149 * @see #ACTION_CONFIRM_PIN_SHORTCUT
150 * @see #ACTION_CONFIRM_PIN_APPWIDGET
Makoto Onuki2d895c32016-12-02 15:48:40 -0800151 */
152 public static final String EXTRA_PIN_ITEM_REQUEST =
153 "android.content.pm.extra.PIN_ITEM_REQUEST";
154
Makoto Onukide3c16c2017-01-26 11:39:31 -0800155 private final Context mContext;
Mathew Inwood8c854f82018-09-14 12:35:36 +0100156 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
Makoto Onukide3c16c2017-01-26 11:39:31 -0800157 private final ILauncherApps mService;
Mathew Inwood5c0d3542018-08-14 13:54:31 +0100158 @UnsupportedAppUsage
Makoto Onukide3c16c2017-01-26 11:39:31 -0800159 private final PackageManager mPm;
160 private final UserManager mUserManager;
Amith Yamasani4f582632014-02-19 14:31:52 -0800161
Jon Miranda2b340a22019-01-25 14:03:49 -0800162 private final List<CallbackMessageHandler> mCallbacks = new ArrayList<>();
163 private final List<SessionCallbackDelegate> mDelegates = new ArrayList<>();
Kenny Guyc01545372014-06-16 14:17:26 +0100164
Mehdi Alizadehb754b7a2020-02-13 20:54:43 -0800165 private final Map<ShortcutChangeCallback, Pair<Executor, IShortcutChangeCallback>>
Mehdi Alizadeh9f680192020-01-16 18:09:24 -0800166 mShortcutChangeCallbacks = new HashMap<>();
167
Kenny Guyc01545372014-06-16 14:17:26 +0100168 /**
169 * Callbacks for package changes to this and related managed profiles.
170 */
Kenny Guyf939dba2014-08-15 15:32:34 +0100171 public static abstract class Callback {
Kenny Guyc01545372014-06-16 14:17:26 +0100172 /**
173 * Indicates that a package was removed from the specified profile.
174 *
Kenny Guyb42c89b2014-07-28 19:20:07 +0100175 * If a package is removed while being updated onPackageChanged will be
176 * called instead.
177 *
Kenny Guyc01545372014-06-16 14:17:26 +0100178 * @param packageName The name of the package that was removed.
179 * @param user The UserHandle of the profile that generated the change.
180 */
181 abstract public void onPackageRemoved(String packageName, UserHandle user);
182
183 /**
184 * Indicates that a package was added to the specified profile.
185 *
Kenny Guyb42c89b2014-07-28 19:20:07 +0100186 * If a package is added while being updated then onPackageChanged will be
187 * called instead.
188 *
Kenny Guyc01545372014-06-16 14:17:26 +0100189 * @param packageName The name of the package that was added.
190 * @param user The UserHandle of the profile that generated the change.
191 */
192 abstract public void onPackageAdded(String packageName, UserHandle user);
193
194 /**
195 * Indicates that a package was modified in the specified profile.
Kenny Guyb42c89b2014-07-28 19:20:07 +0100196 * This can happen, for example, when the package is updated or when
197 * one or more components are enabled or disabled.
Kenny Guyc01545372014-06-16 14:17:26 +0100198 *
199 * @param packageName The name of the package that has changed.
200 * @param user The UserHandle of the profile that generated the change.
201 */
202 abstract public void onPackageChanged(String packageName, UserHandle user);
203
204 /**
205 * Indicates that one or more packages have become available. For
206 * example, this can happen when a removable storage card has
207 * reappeared.
208 *
209 * @param packageNames The names of the packages that have become
210 * available.
211 * @param user The UserHandle of the profile that generated the change.
212 * @param replacing Indicates whether these packages are replacing
213 * existing ones.
214 */
215 abstract public void onPackagesAvailable(String[] packageNames, UserHandle user,
216 boolean replacing);
217
218 /**
219 * Indicates that one or more packages have become unavailable. For
220 * example, this can happen when a removable storage card has been
221 * removed.
222 *
223 * @param packageNames The names of the packages that have become
224 * unavailable.
225 * @param user The UserHandle of the profile that generated the change.
226 * @param replacing Indicates whether the packages are about to be
227 * replaced with new versions.
228 */
229 abstract public void onPackagesUnavailable(String[] packageNames, UserHandle user,
230 boolean replacing);
Kenny Guy77242752016-01-15 13:29:06 +0000231
232 /**
233 * Indicates that one or more packages have been suspended. For
234 * example, this can happen when a Device Administrator suspends
235 * an applicaton.
236 *
Suprabh Shukla19b41f32018-03-26 22:35:13 -0700237 * <p>Note: On devices running {@link android.os.Build.VERSION_CODES#P Android P} or higher,
Suprabh Shukla96212bc2018-04-10 15:04:51 -0700238 * any apps that override {@link #onPackagesSuspended(String[], UserHandle, Bundle)} will
Suprabh Shukla19b41f32018-03-26 22:35:13 -0700239 * not receive this callback.
240 *
Kenny Guy77242752016-01-15 13:29:06 +0000241 * @param packageNames The names of the packages that have just been
242 * suspended.
243 * @param user The UserHandle of the profile that generated the change.
244 */
245 public void onPackagesSuspended(String[] packageNames, UserHandle user) {
246 }
247
248 /**
Suprabh Shukla19b41f32018-03-26 22:35:13 -0700249 * Indicates that one or more packages have been suspended. A device administrator or an app
250 * with {@code android.permission.SUSPEND_APPS} can do this.
251 *
Suprabh Shukla96212bc2018-04-10 15:04:51 -0700252 * <p>A suspending app with the permission {@code android.permission.SUSPEND_APPS} can
253 * optionally provide a {@link Bundle} of extra information that it deems helpful for the
254 * launcher to handle the suspended state of these packages. The contents of this
Suprabh Shukla3e03ab92018-04-11 16:03:49 -0700255 * {@link Bundle} are supposed to be a contract between the suspending app and the launcher.
Suprabh Shukla19b41f32018-03-26 22:35:13 -0700256 *
Suprabh Shukla96212bc2018-04-10 15:04:51 -0700257 * @param packageNames The names of the packages that have just been suspended.
258 * @param user the user for which the given packages were suspended.
259 * @param launcherExtras A {@link Bundle} of extras for the launcher, if provided to the
260 * system, {@code null} otherwise.
Suprabh Shukla19b41f32018-03-26 22:35:13 -0700261 * @see PackageManager#isPackageSuspended()
262 * @see #getSuspendedPackageLauncherExtras(String, UserHandle)
Suprabh Shuklad3278442019-08-27 15:58:03 -0700263 * @deprecated {@code launcherExtras} should be obtained by using
264 * {@link #getSuspendedPackageLauncherExtras(String, UserHandle)}. For all other cases,
265 * {@link #onPackagesSuspended(String[], UserHandle)} should be used.
Suprabh Shukla19b41f32018-03-26 22:35:13 -0700266 */
Suprabh Shuklad3278442019-08-27 15:58:03 -0700267 @Deprecated
Suprabh Shukla96212bc2018-04-10 15:04:51 -0700268 public void onPackagesSuspended(String[] packageNames, UserHandle user,
269 @Nullable Bundle launcherExtras) {
Suprabh Shukla19b41f32018-03-26 22:35:13 -0700270 onPackagesSuspended(packageNames, user);
271 }
272
273 /**
Kenny Guy77242752016-01-15 13:29:06 +0000274 * Indicates that one or more packages have been unsuspended. For
275 * example, this can happen when a Device Administrator unsuspends
276 * an applicaton.
277 *
278 * @param packageNames The names of the packages that have just been
279 * unsuspended.
280 * @param user The UserHandle of the profile that generated the change.
281 */
282 public void onPackagesUnsuspended(String[] packageNames, UserHandle user) {
283 }
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800284
285 /**
Makoto Onukife9c9662016-07-25 15:12:23 -0700286 * Indicates that one or more shortcuts of any kind (dynamic, pinned, or manifest)
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800287 * have been added, updated or removed.
288 *
Makoto Onuki2d5b4652016-03-11 16:09:54 -0800289 * <p>Only the applications that are allowed to access the shortcut information,
290 * as defined in {@link #hasShortcutHostPermission()}, will receive it.
291 *
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800292 * @param packageName The name of the package that has the shortcuts.
Makoto Onukife9c9662016-07-25 15:12:23 -0700293 * @param shortcuts All shortcuts from the package (dynamic, manifest and/or pinned).
294 * Only "key" information will be provided, as defined in
Makoto Onuki4d6b87f2016-06-17 13:47:40 -0700295 * {@link ShortcutInfo#hasKeyFieldsOnly()}.
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800296 * @param user The UserHandle of the profile that generated the change.
Makoto Onuki4a910962016-07-07 13:57:34 -0700297 *
298 * @see ShortcutManager
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800299 */
300 public void onShortcutsChanged(@NonNull String packageName,
301 @NonNull List<ShortcutInfo> shortcuts, @NonNull UserHandle user) {
302 }
303 }
304
305 /**
306 * Represents a query passed to {@link #getShortcuts(ShortcutQuery, UserHandle)}.
307 */
308 public static class ShortcutQuery {
309 /**
310 * Include dynamic shortcuts in the result.
311 */
Makoto Onukib5a012f2016-06-21 11:13:53 -0700312 public static final int FLAG_MATCH_DYNAMIC = 1 << 0;
313
314 /** @hide kept for unit tests */
315 @Deprecated
316 public static final int FLAG_GET_DYNAMIC = FLAG_MATCH_DYNAMIC;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800317
318 /**
319 * Include pinned shortcuts in the result.
Makoto Onuki88b4dcc2017-12-07 15:53:56 -0800320 *
321 * <p>If you are the selected assistant app, and wishes to fetch all shortcuts that the
322 * user owns on the launcher (or by other launchers, in case the user has multiple), use
323 * {@link #FLAG_MATCH_PINNED_BY_ANY_LAUNCHER} instead.
324 *
325 * <p>If you're a regular launcher app, there's no way to get shortcuts pinned by other
326 * launchers, and {@link #FLAG_MATCH_PINNED_BY_ANY_LAUNCHER} will be ignored. So use this
327 * flag to get own pinned shortcuts.
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800328 */
Makoto Onukib5a012f2016-06-21 11:13:53 -0700329 public static final int FLAG_MATCH_PINNED = 1 << 1;
330
331 /** @hide kept for unit tests */
332 @Deprecated
333 public static final int FLAG_GET_PINNED = FLAG_MATCH_PINNED;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800334
335 /**
Makoto Onuki22fcc682016-05-17 14:52:19 -0700336 * Include manifest shortcuts in the result.
337 */
Makoto Onukib5a012f2016-06-21 11:13:53 -0700338 public static final int FLAG_MATCH_MANIFEST = 1 << 3;
339
Mehdi Alizadeh505fb762020-01-21 17:26:24 -0800340 /**
341 * Include cached shortcuts in the result.
342 */
343 public static final int FLAG_MATCH_CACHED = 1 << 4;
344
Makoto Onukib5a012f2016-06-21 11:13:53 -0700345 /** @hide kept for unit tests */
346 @Deprecated
347 public static final int FLAG_GET_MANIFEST = FLAG_MATCH_MANIFEST;
Makoto Onuki22fcc682016-05-17 14:52:19 -0700348
Hakan Seyalioglu58fc95d2016-12-13 15:23:22 -0800349 /**
Makoto Onuki35559d62017-11-06 16:26:32 -0800350 * Include all pinned shortcuts by any launchers, not just by the caller,
Makoto Onuki634cecb2017-10-13 17:10:48 -0700351 * in the result.
Makoto Onuki35559d62017-11-06 16:26:32 -0800352 *
Makoto Onuki88b4dcc2017-12-07 15:53:56 -0800353 * <p>The caller must be the selected assistant app to use this flag, or have the system
Makoto Onuki35559d62017-11-06 16:26:32 -0800354 * {@code ACCESS_SHORTCUTS} permission.
Makoto Onuki88b4dcc2017-12-07 15:53:56 -0800355 *
356 * <p>If you are the selected assistant app, and wishes to fetch all shortcuts that the
357 * user owns on the launcher (or by other launchers, in case the user has multiple), use
358 * {@link #FLAG_MATCH_PINNED_BY_ANY_LAUNCHER} instead.
359 *
360 * <p>If you're a regular launcher app (or any app that's not the selected assistant app)
361 * then this flag will be ignored.
Makoto Onuki634cecb2017-10-13 17:10:48 -0700362 */
Makoto Onuki35559d62017-11-06 16:26:32 -0800363 public static final int FLAG_MATCH_PINNED_BY_ANY_LAUNCHER = 1 << 10;
Makoto Onuki634cecb2017-10-13 17:10:48 -0700364
365 /**
Mehdi Alizadeh505fb762020-01-21 17:26:24 -0800366 * FLAG_MATCH_DYNAMIC | FLAG_MATCH_PINNED | FLAG_MATCH_MANIFEST | FLAG_MATCH_CACHED
Hakan Seyalioglu58fc95d2016-12-13 15:23:22 -0800367 * @hide
368 */
Makoto Onukib5a012f2016-06-21 11:13:53 -0700369 public static final int FLAG_MATCH_ALL_KINDS =
Mehdi Alizadeh505fb762020-01-21 17:26:24 -0800370 FLAG_MATCH_DYNAMIC | FLAG_MATCH_PINNED | FLAG_MATCH_MANIFEST | FLAG_MATCH_CACHED;
Makoto Onuki634cecb2017-10-13 17:10:48 -0700371
372 /**
373 * FLAG_MATCH_DYNAMIC | FLAG_MATCH_PINNED | FLAG_MATCH_MANIFEST | FLAG_MATCH_ALL_PINNED
374 * @hide
375 */
376 public static final int FLAG_MATCH_ALL_KINDS_WITH_ALL_PINNED =
Makoto Onuki35559d62017-11-06 16:26:32 -0800377 FLAG_MATCH_ALL_KINDS | FLAG_MATCH_PINNED_BY_ANY_LAUNCHER;
Makoto Onuki4d6b87f2016-06-17 13:47:40 -0700378
Makoto Onukib5a012f2016-06-21 11:13:53 -0700379 /** @hide kept for unit tests */
380 @Deprecated
381 public static final int FLAG_GET_ALL_KINDS = FLAG_MATCH_ALL_KINDS;
382
Makoto Onuki22fcc682016-05-17 14:52:19 -0700383 /**
Makoto Onukife9c9662016-07-25 15:12:23 -0700384 * Requests "key" fields only. See {@link ShortcutInfo#hasKeyFieldsOnly()}'s javadoc to
385 * see which fields fields "key".
386 * This allows quicker access to shortcut information in order to
387 * determine whether the caller's in-memory cache needs to be updated.
Makoto Onuki4a910962016-07-07 13:57:34 -0700388 *
Makoto Onukife9c9662016-07-25 15:12:23 -0700389 * <p>Typically, launcher applications cache all or most shortcut information
390 * in memory in order to show shortcuts without a delay.
391 *
392 * When a given launcher application wants to update its cache, such as when its process
393 * restarts, it can fetch shortcut information with this flag.
394 * The application can then check {@link ShortcutInfo#getLastChangedTimestamp()} for each
395 * shortcut, fetching a shortcut's non-key information only if that shortcut has been
396 * updated.
Makoto Onuki4a910962016-07-07 13:57:34 -0700397 *
398 * @see ShortcutManager
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800399 */
400 public static final int FLAG_GET_KEY_FIELDS_ONLY = 1 << 2;
401
402 /** @hide */
Jeff Sharkeyce8db992017-12-13 20:05:05 -0700403 @IntDef(flag = true, prefix = { "FLAG_" }, value = {
404 FLAG_MATCH_DYNAMIC,
405 FLAG_MATCH_PINNED,
406 FLAG_MATCH_MANIFEST,
Mehdi Alizadeh505fb762020-01-21 17:26:24 -0800407 FLAG_MATCH_CACHED,
Jeff Sharkeyce8db992017-12-13 20:05:05 -0700408 FLAG_GET_KEY_FIELDS_ONLY,
Jeff Sharkeyce8db992017-12-13 20:05:05 -0700409 })
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800410 @Retention(RetentionPolicy.SOURCE)
411 public @interface QueryFlags {}
412
413 long mChangedSince;
414
415 @Nullable
416 String mPackage;
417
418 @Nullable
Makoto Onukiabe84422016-04-07 09:41:19 -0700419 List<String> mShortcutIds;
420
421 @Nullable
Mehdi Alizadehae808ff2020-01-21 13:39:53 -0800422 List<LocusId> mLocusIds;
423
424 @Nullable
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800425 ComponentName mActivity;
426
427 @QueryFlags
428 int mQueryFlags;
429
430 public ShortcutQuery() {
431 }
432
433 /**
Makoto Onukife9c9662016-07-25 15:12:23 -0700434 * If non-zero, returns only shortcuts that have been added or updated
435 * since the given timestamp, expressed in milliseconds since the Epoch&mdash;see
436 * {@link System#currentTimeMillis()}.
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800437 */
Makoto Onuki22fcc682016-05-17 14:52:19 -0700438 public ShortcutQuery setChangedSince(long changedSince) {
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800439 mChangedSince = changedSince;
Makoto Onuki22fcc682016-05-17 14:52:19 -0700440 return this;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800441 }
442
443 /**
444 * If non-null, returns only shortcuts from the package.
445 */
Makoto Onuki22fcc682016-05-17 14:52:19 -0700446 public ShortcutQuery setPackage(@Nullable String packageName) {
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800447 mPackage = packageName;
Makoto Onuki22fcc682016-05-17 14:52:19 -0700448 return this;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800449 }
450
451 /**
Makoto Onukiabe84422016-04-07 09:41:19 -0700452 * If non-null, return only the specified shortcuts by ID. When setting this field,
Makoto Onuki4a910962016-07-07 13:57:34 -0700453 * a package name must also be set with {@link #setPackage}.
Makoto Onukiabe84422016-04-07 09:41:19 -0700454 */
Makoto Onuki22fcc682016-05-17 14:52:19 -0700455 public ShortcutQuery setShortcutIds(@Nullable List<String> shortcutIds) {
Makoto Onukiabe84422016-04-07 09:41:19 -0700456 mShortcutIds = shortcutIds;
Makoto Onuki22fcc682016-05-17 14:52:19 -0700457 return this;
Makoto Onukiabe84422016-04-07 09:41:19 -0700458 }
459
460 /**
Mehdi Alizadehae808ff2020-01-21 13:39:53 -0800461 * If non-null, return only the specified shortcuts by locus ID. When setting this field,
462 * a package name must also be set with {@link #setPackage}.
463 *
464 * @hide
465 */
466 @SystemApi
467 @NonNull
468 public ShortcutQuery setLocusIds(@Nullable List<LocusId> locusIds) {
469 mLocusIds = locusIds;
470 return this;
471 }
472
473 /**
Makoto Onuki22fcc682016-05-17 14:52:19 -0700474 * If non-null, returns only shortcuts associated with the activity; i.e.
475 * {@link ShortcutInfo}s whose {@link ShortcutInfo#getActivity()} are equal
476 * to {@code activity}.
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800477 */
Makoto Onuki22fcc682016-05-17 14:52:19 -0700478 public ShortcutQuery setActivity(@Nullable ComponentName activity) {
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800479 mActivity = activity;
Makoto Onuki22fcc682016-05-17 14:52:19 -0700480 return this;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800481 }
482
Hakan Seyalioglu58fc95d2016-12-13 15:23:22 -0800483 /**
Makoto Onukife9c9662016-07-25 15:12:23 -0700484 * Set query options. At least one of the {@code MATCH} flags should be set. Otherwise,
485 * no shortcuts will be returned.
Makoto Onuki4a910962016-07-07 13:57:34 -0700486 *
Makoto Onukife9c9662016-07-25 15:12:23 -0700487 * <ul>
488 * <li>{@link #FLAG_MATCH_DYNAMIC}
489 * <li>{@link #FLAG_MATCH_PINNED}
490 * <li>{@link #FLAG_MATCH_MANIFEST}
Mehdi Alizadeh505fb762020-01-21 17:26:24 -0800491 * <li>{@link #FLAG_MATCH_CACHED}
Makoto Onukife9c9662016-07-25 15:12:23 -0700492 * <li>{@link #FLAG_GET_KEY_FIELDS_ONLY}
493 * </ul>
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800494 */
Makoto Onuki22fcc682016-05-17 14:52:19 -0700495 public ShortcutQuery setQueryFlags(@QueryFlags int queryFlags) {
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800496 mQueryFlags = queryFlags;
Makoto Onuki22fcc682016-05-17 14:52:19 -0700497 return this;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800498 }
Kenny Guyc01545372014-06-16 14:17:26 +0100499 }
Amith Yamasani4f582632014-02-19 14:31:52 -0800500
Mehdi Alizadeh9f680192020-01-16 18:09:24 -0800501 /**
502 * Callbacks for shortcut changes to this and related managed profiles.
503 *
504 * @hide
505 */
506 public interface ShortcutChangeCallback {
507 /**
508 * Indicates that one or more shortcuts, that match the {@link ShortcutQuery} used to
509 * register this callback, have been added or updated.
510 * @see LauncherApps#registerShortcutChangeCallback(ShortcutChangeCallback, ShortcutQuery)
511 *
512 * <p>Only the applications that are allowed to access the shortcut information,
513 * as defined in {@link #hasShortcutHostPermission()}, will receive it.
514 *
515 * @param packageName The name of the package that has the shortcuts.
516 * @param shortcuts Shortcuts from the package that have updated or added. Only "key"
517 * information will be provided, as defined in {@link ShortcutInfo#hasKeyFieldsOnly()}.
518 * @param user The UserHandle of the profile that generated the change.
519 *
520 * @see ShortcutManager
521 */
522 default void onShortcutsAddedOrUpdated(@NonNull String packageName,
523 @NonNull List<ShortcutInfo> shortcuts, @NonNull UserHandle user) {}
524
525 /**
526 * Indicates that one or more shortcuts, that match the {@link ShortcutQuery} used to
527 * register this callback, have been removed.
528 * @see LauncherApps#registerShortcutChangeCallback(ShortcutChangeCallback, ShortcutQuery)
529 *
530 * <p>Only the applications that are allowed to access the shortcut information,
531 * as defined in {@link #hasShortcutHostPermission()}, will receive it.
532 *
533 * @param packageName The name of the package that has the shortcuts.
534 * @param shortcuts Shortcuts from the package that have been removed. Only "key"
535 * information will be provided, as defined in {@link ShortcutInfo#hasKeyFieldsOnly()}.
536 * @param user The UserHandle of the profile that generated the change.
537 *
538 * @see ShortcutManager
539 */
540 default void onShortcutsRemoved(@NonNull String packageName,
541 @NonNull List<ShortcutInfo> shortcuts, @NonNull UserHandle user) {}
542 }
543
544 /**
545 * Callback proxy class for {@link ShortcutChangeCallback}
546 *
547 * @hide
548 */
549 private static class ShortcutChangeCallbackProxy extends
550 android.content.pm.IShortcutChangeCallback.Stub {
551 private final WeakReference<Pair<Executor, ShortcutChangeCallback>> mRemoteReferences;
552
Mehdi Alizadehb754b7a2020-02-13 20:54:43 -0800553 ShortcutChangeCallbackProxy(Executor executor, ShortcutChangeCallback callback) {
554 mRemoteReferences = new WeakReference<>(new Pair<>(executor, callback));
Mehdi Alizadeh9f680192020-01-16 18:09:24 -0800555 }
556
557 @Override
558 public void onShortcutsAddedOrUpdated(@NonNull String packageName,
559 @NonNull List<ShortcutInfo> shortcuts, @NonNull UserHandle user) {
560 Pair<Executor, ShortcutChangeCallback> remoteReferences = mRemoteReferences.get();
561 if (remoteReferences == null) {
562 // Binder is dead.
563 return;
564 }
565
566 final Executor executor = remoteReferences.first;
567 final ShortcutChangeCallback callback = remoteReferences.second;
568 executor.execute(
569 PooledLambda.obtainRunnable(ShortcutChangeCallback::onShortcutsAddedOrUpdated,
570 callback, packageName, shortcuts, user).recycleOnUse());
571 }
572
573 @Override
574 public void onShortcutsRemoved(@NonNull String packageName,
575 @NonNull List<ShortcutInfo> shortcuts, @NonNull UserHandle user) {
576 Pair<Executor, ShortcutChangeCallback> remoteReferences = mRemoteReferences.get();
577 if (remoteReferences == null) {
578 // Binder is dead.
579 return;
580 }
581
582 final Executor executor = remoteReferences.first;
583 final ShortcutChangeCallback callback = remoteReferences.second;
584 executor.execute(
585 PooledLambda.obtainRunnable(ShortcutChangeCallback::onShortcutsRemoved,
586 callback, packageName, shortcuts, user).recycleOnUse());
587 }
588 }
589
Amith Yamasani4f582632014-02-19 14:31:52 -0800590 /** @hide */
591 public LauncherApps(Context context, ILauncherApps service) {
592 mContext = context;
593 mService = service;
Amith Yamasanie781c812014-05-28 15:28:18 -0700594 mPm = context.getPackageManager();
Makoto Onukide3c16c2017-01-26 11:39:31 -0800595 mUserManager = context.getSystemService(UserManager.class);
Amith Yamasani4f582632014-02-19 14:31:52 -0800596 }
597
Makoto Onuki5ba0d3e2016-04-11 14:03:46 -0700598 /** @hide */
599 @TestApi
600 public LauncherApps(Context context) {
601 this(context, ILauncherApps.Stub.asInterface(
602 ServiceManager.getService(Context.LAUNCHER_APPS_SERVICE)));
603 }
604
Amith Yamasani4f582632014-02-19 14:31:52 -0800605 /**
arangelov08abd0f2020-01-24 17:09:56 +0000606 * Show an error log on logcat, when the calling user is a managed profile, the target
607 * user is different from the calling user, and it is not called from a package that has the
608 * {@link permission.INTERACT_ACROSS_USERS_FULL} permission, in order to help
609 * developers to detect it.
Makoto Onukide3c16c2017-01-26 11:39:31 -0800610 */
611 private void logErrorForInvalidProfileAccess(@NonNull UserHandle target) {
arangelov08abd0f2020-01-24 17:09:56 +0000612 if (UserHandle.myUserId() != target.getIdentifier() && mUserManager.isManagedProfile()
613 && mContext.checkSelfPermission(permission.INTERACT_ACROSS_USERS_FULL)
614 != PackageManager.PERMISSION_GRANTED) {
Makoto Onuki3cc7cd12017-04-03 12:48:42 -0700615 Log.w(TAG, "Accessing other profiles/users from managed profile is no longer allowed.");
Makoto Onukide3c16c2017-01-26 11:39:31 -0800616 }
617 }
618
619 /**
Makoto Onukiaecbd032017-01-19 12:11:11 -0800620 * Return a list of profiles that the caller can access via the {@link LauncherApps} APIs.
621 *
622 * <p>If the caller is running on a managed profile, it'll return only the current profile.
623 * Otherwise it'll return the same list as {@link UserManager#getUserProfiles()} would.
624 */
625 public List<UserHandle> getProfiles() {
Makoto Onukide3c16c2017-01-26 11:39:31 -0800626 if (mUserManager.isManagedProfile()) {
Makoto Onukiaecbd032017-01-19 12:11:11 -0800627 // If it's a managed profile, only return the current profile.
628 final List result = new ArrayList(1);
629 result.add(android.os.Process.myUserHandle());
630 return result;
631 } else {
Makoto Onukide3c16c2017-01-26 11:39:31 -0800632 return mUserManager.getUserProfiles();
Makoto Onukiaecbd032017-01-19 12:11:11 -0800633 }
634 }
635
636 /**
Kevin Hufnagle25266af2019-08-14 17:23:58 -0700637 * Retrieves a list of activities that specify {@link Intent#ACTION_MAIN} and
638 * {@link Intent#CATEGORY_LAUNCHER}, across all apps, for a specified user. If an app doesn't
639 * have any activities that specify <code>ACTION_MAIN</code> or <code>CATEGORY_LAUNCHER</code>,
640 * the system adds a synthesized activity to the list. This synthesized activity represents the
641 * app's details page within system settings.
642 *
643 * <p class="note"><b>Note: </b>It's possible for system apps, such as app stores, to prevent
644 * the system from adding synthesized activities to the returned list.</p>
645 *
646 * <p>As of <a href="/reference/android/os/Build.VERSION_CODES.html#Q">Android Q</a>, at least
647 * one of the app's activities or synthesized activities appears in the returned list unless the
648 * app satisfies at least one of the following conditions:</p>
649 * <ul>
650 * <li>The app is a system app.</li>
651 * <li>The app doesn't request any <a href="/guide/topics/permissions/overview">permissions</a>.
652 * </li>
Kevin Hufnagleb8779b82019-09-13 02:18:44 +0000653 * <li>The app doesn't have a <em>launcher activity</em> that is enabled by default. A launcher
654 * activity has an intent containing the <code>ACTION_MAIN</code> action and the
655 * <code>CATEGORY_LAUNCHER</code> category.</li>
Kevin Hufnagle25266af2019-08-14 17:23:58 -0700656 * </ul>
657 *
658 * <p>Additionally, the system hides synthesized activities for some or all apps in the
659 * following enterprise-related cases:</p>
660 * <ul>
661 * <li>If the device is a
662 * <a href="https://developers.google.com/android/work/overview#company-owned-devices-for-knowledge-workers">fully
663 * managed device</a>, no synthesized activities for any app appear in the returned list.</li>
664 * <li>If the current user has a
665 * <a href="https://developers.google.com/android/work/overview#employee-owned-devices-byod">work
666 * profile</a>, no synthesized activities for the user's work apps appear in the returned
667 * list.</li>
668 * </ul>
Amith Yamasani4f582632014-02-19 14:31:52 -0800669 *
670 * @param packageName The specific package to query. If null, it checks all installed packages
671 * in the profile.
672 * @param user The UserHandle of the profile.
673 * @return List of launchable activities. Can be an empty list but will not be null.
674 */
675 public List<LauncherActivityInfo> getActivityList(String packageName, UserHandle user) {
Makoto Onukide3c16c2017-01-26 11:39:31 -0800676 logErrorForInvalidProfileAccess(user);
Amith Yamasani4f582632014-02-19 14:31:52 -0800677 try {
Makoto Onuki3a2541e2017-01-24 09:00:15 -0800678 return convertToActivityList(mService.getLauncherActivities(mContext.getPackageName(),
679 packageName, user), user);
Amith Yamasani4f582632014-02-19 14:31:52 -0800680 } catch (RemoteException re) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700681 throw re.rethrowFromSystemServer();
Amith Yamasani4f582632014-02-19 14:31:52 -0800682 }
Amith Yamasani4f582632014-02-19 14:31:52 -0800683 }
684
Amith Yamasani4f582632014-02-19 14:31:52 -0800685 /**
686 * Returns the activity info for a given intent and user handle, if it resolves. Otherwise it
687 * returns null.
688 *
689 * @param intent The intent to find a match for.
690 * @param user The profile to look in for a match.
691 * @return An activity info object if there is a match.
692 */
693 public LauncherActivityInfo resolveActivity(Intent intent, UserHandle user) {
Makoto Onukide3c16c2017-01-26 11:39:31 -0800694 logErrorForInvalidProfileAccess(user);
Amith Yamasani4f582632014-02-19 14:31:52 -0800695 try {
Makoto Onuki3a2541e2017-01-24 09:00:15 -0800696 ActivityInfo ai = mService.resolveActivity(mContext.getPackageName(),
697 intent.getComponent(), user);
Sunny Goyal45d3e972016-03-31 12:38:17 -0700698 if (ai != null) {
699 LauncherActivityInfo info = new LauncherActivityInfo(mContext, ai, user);
Amith Yamasani4f582632014-02-19 14:31:52 -0800700 return info;
701 }
702 } catch (RemoteException re) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700703 throw re.rethrowFromSystemServer();
Amith Yamasani4f582632014-02-19 14:31:52 -0800704 }
705 return null;
706 }
707
708 /**
Kenny Guyf939dba2014-08-15 15:32:34 +0100709 * Starts a Main activity in the specified profile.
Amith Yamasani4f582632014-02-19 14:31:52 -0800710 *
711 * @param component The ComponentName of the activity to launch
Amith Yamasanie781c812014-05-28 15:28:18 -0700712 * @param user The UserHandle of the profile
713 * @param sourceBounds The Rect containing the source bounds of the clicked icon
714 * @param opts Options to pass to startActivity
715 */
Kenny Guyf939dba2014-08-15 15:32:34 +0100716 public void startMainActivity(ComponentName component, UserHandle user, Rect sourceBounds,
Amith Yamasanie781c812014-05-28 15:28:18 -0700717 Bundle opts) {
Makoto Onukide3c16c2017-01-26 11:39:31 -0800718 logErrorForInvalidProfileAccess(user);
Amith Yamasani5abdbb62014-04-08 17:23:46 -0700719 if (DEBUG) {
Kenny Guyf939dba2014-08-15 15:32:34 +0100720 Log.i(TAG, "StartMainActivity " + component + " " + user.getIdentifier());
Amith Yamasani5abdbb62014-04-08 17:23:46 -0700721 }
Amith Yamasani4f582632014-02-19 14:31:52 -0800722 try {
Makoto Onuki1a342742018-04-26 14:56:59 -0700723 mService.startActivityAsUser(mContext.getIApplicationThread(),
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -0800724 mContext.getPackageName(), mContext.getAttributionTag(),
Makoto Onuki3a2541e2017-01-24 09:00:15 -0800725 component, sourceBounds, opts, user);
Amith Yamasani4f582632014-02-19 14:31:52 -0800726 } catch (RemoteException re) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700727 throw re.rethrowFromSystemServer();
Amith Yamasani4f582632014-02-19 14:31:52 -0800728 }
729 }
730
731 /**
Jon Miranda2b340a22019-01-25 14:03:49 -0800732 * Starts an activity to show the details of the specified session.
733 *
734 * @param sessionInfo The SessionInfo of the session
735 * @param sourceBounds The Rect containing the source bounds of the clicked icon
736 * @param opts Options to pass to startActivity
737 */
Jon Miranda93505982019-03-08 09:33:42 -0800738 public void startPackageInstallerSessionDetailsActivity(@NonNull SessionInfo sessionInfo,
739 @Nullable Rect sourceBounds, @Nullable Bundle opts) {
Jon Miranda2b340a22019-01-25 14:03:49 -0800740 try {
741 mService.startSessionDetailsActivityAsUser(mContext.getIApplicationThread(),
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -0800742 mContext.getPackageName(), mContext.getAttributionTag(), sessionInfo,
743 sourceBounds, opts, sessionInfo.getUser());
Jon Miranda2b340a22019-01-25 14:03:49 -0800744 } catch (RemoteException re) {
745 throw re.rethrowFromSystemServer();
746 }
747 }
748
749 /**
Kenny Guy466d2032014-07-23 12:23:35 +0100750 * Starts the settings activity to show the application details for a
751 * package in the specified profile.
752 *
753 * @param component The ComponentName of the package to launch settings for.
754 * @param user The UserHandle of the profile
755 * @param sourceBounds The Rect containing the source bounds of the clicked icon
756 * @param opts Options to pass to startActivity
757 */
Kenny Guyf939dba2014-08-15 15:32:34 +0100758 public void startAppDetailsActivity(ComponentName component, UserHandle user,
Kenny Guy466d2032014-07-23 12:23:35 +0100759 Rect sourceBounds, Bundle opts) {
Makoto Onukide3c16c2017-01-26 11:39:31 -0800760 logErrorForInvalidProfileAccess(user);
Kenny Guy466d2032014-07-23 12:23:35 +0100761 try {
Makoto Onuki1a342742018-04-26 14:56:59 -0700762 mService.showAppDetailsAsUser(mContext.getIApplicationThread(),
Philip P. Moltmann12ac3f42020-03-05 15:01:29 -0800763 mContext.getPackageName(), mContext.getAttributionTag(),
Makoto Onuki3a2541e2017-01-24 09:00:15 -0800764 component, sourceBounds, opts, user);
Kenny Guy466d2032014-07-23 12:23:35 +0100765 } catch (RemoteException re) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700766 throw re.rethrowFromSystemServer();
Kenny Guy466d2032014-07-23 12:23:35 +0100767 }
768 }
769
770 /**
Sunny Goyala6be88a2017-01-12 16:27:58 -0800771 * Retrieves a list of config activities for creating {@link ShortcutInfo}.
772 *
773 * @param packageName The specific package to query. If null, it checks all installed packages
774 * in the profile.
775 * @param user The UserHandle of the profile.
776 * @return List of config activities. Can be an empty list but will not be null.
777 *
778 * @see Intent#ACTION_CREATE_SHORTCUT
779 * @see #getShortcutConfigActivityIntent(LauncherActivityInfo)
780 */
781 public List<LauncherActivityInfo> getShortcutConfigActivityList(@Nullable String packageName,
782 @NonNull UserHandle user) {
Makoto Onukide3c16c2017-01-26 11:39:31 -0800783 logErrorForInvalidProfileAccess(user);
Sunny Goyala6be88a2017-01-12 16:27:58 -0800784 try {
Makoto Onuki3a2541e2017-01-24 09:00:15 -0800785 return convertToActivityList(mService.getShortcutConfigActivities(
786 mContext.getPackageName(), packageName, user),
Sunny Goyala6be88a2017-01-12 16:27:58 -0800787 user);
788 } catch (RemoteException re) {
789 throw re.rethrowFromSystemServer();
790 }
791 }
792
793 private List<LauncherActivityInfo> convertToActivityList(
794 @Nullable ParceledListSlice<ResolveInfo> activities, UserHandle user) {
795 if (activities == null) {
796 return Collections.EMPTY_LIST;
797 }
798 ArrayList<LauncherActivityInfo> lais = new ArrayList<>();
799 for (ResolveInfo ri : activities.getList()) {
800 LauncherActivityInfo lai = new LauncherActivityInfo(mContext, ri.activityInfo, user);
801 if (DEBUG) {
802 Log.v(TAG, "Returning activity for profile " + user + " : "
803 + lai.getComponentName());
804 }
805 lais.add(lai);
806 }
807 return lais;
808 }
809
810 /**
811 * Returns an intent sender which can be used to start the configure activity for creating
812 * custom shortcuts. Use this method if the provider is in another profile as you are not
813 * allowed to start an activity in another profile.
814 *
815 * <p>The caller should receive {@link PinItemRequest} in onActivityResult on
816 * {@link android.app.Activity#RESULT_OK}.
817 *
818 * <p>Callers must be allowed to access the shortcut information, as defined in {@link
819 * #hasShortcutHostPermission()}.
820 *
821 * @param info a configuration activity returned by {@link #getShortcutConfigActivityList}
822 *
823 * @throws IllegalStateException when the user is locked or not running.
824 * @throws SecurityException if {@link #hasShortcutHostPermission()} is false.
825 *
826 * @see #getPinItemRequest(Intent)
827 * @see Intent#ACTION_CREATE_SHORTCUT
828 * @see android.app.Activity#startIntentSenderForResult
829 */
Makoto Onukide3c16c2017-01-26 11:39:31 -0800830 @Nullable
Sunny Goyala6be88a2017-01-12 16:27:58 -0800831 public IntentSender getShortcutConfigActivityIntent(@NonNull LauncherActivityInfo info) {
832 try {
833 return mService.getShortcutConfigActivityIntent(
834 mContext.getPackageName(), info.getComponentName(), info.getUser());
835 } catch (RemoteException re) {
836 throw re.rethrowFromSystemServer();
837 }
838 }
839
840 /**
Kenny Guy53fa4ec2014-04-29 14:24:18 +0100841 * Checks if the package is installed and enabled for a profile.
842 *
843 * @param packageName The package to check.
844 * @param user The UserHandle of the profile.
845 *
846 * @return true if the package exists and is enabled.
847 */
Kenny Guyf939dba2014-08-15 15:32:34 +0100848 public boolean isPackageEnabled(String packageName, UserHandle user) {
Makoto Onukide3c16c2017-01-26 11:39:31 -0800849 logErrorForInvalidProfileAccess(user);
Kenny Guy53fa4ec2014-04-29 14:24:18 +0100850 try {
Makoto Onuki3a2541e2017-01-24 09:00:15 -0800851 return mService.isPackageEnabled(mContext.getPackageName(), packageName, user);
Kenny Guy53fa4ec2014-04-29 14:24:18 +0100852 } catch (RemoteException re) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700853 throw re.rethrowFromSystemServer();
Kenny Guy53fa4ec2014-04-29 14:24:18 +0100854 }
855 }
856
857 /**
Suprabh Shukla19b41f32018-03-26 22:35:13 -0700858 * Gets the launcher extras supplied to the system when the given package was suspended via
859 * {@code PackageManager#setPackagesSuspended(String[], boolean, PersistableBundle,
860 * PersistableBundle, String)}.
861 *
Suprabh Shukla96212bc2018-04-10 15:04:51 -0700862 * <p>The contents of this {@link Bundle} are supposed to be a contract between the suspending
863 * app and the launcher.
864 *
Suprabh Shukla19b41f32018-03-26 22:35:13 -0700865 * <p>Note: This just returns whatever extras were provided to the system, <em>which might
866 * even be {@code null}.</em>
867 *
868 * @param packageName The package for which to fetch the launcher extras.
869 * @param user The {@link UserHandle} of the profile.
870 * @return A {@link Bundle} of launcher extras. Or {@code null} if the package is not currently
871 * suspended.
872 *
Suprabh Shukla96212bc2018-04-10 15:04:51 -0700873 * @see Callback#onPackagesSuspended(String[], UserHandle, Bundle)
Suprabh Shukla19b41f32018-03-26 22:35:13 -0700874 * @see PackageManager#isPackageSuspended()
875 */
876 public @Nullable Bundle getSuspendedPackageLauncherExtras(String packageName, UserHandle user) {
877 logErrorForInvalidProfileAccess(user);
878 try {
879 return mService.getSuspendedPackageLauncherExtras(packageName, user);
880 } catch (RemoteException re) {
881 throw re.rethrowFromSystemServer();
882 }
883 }
884
885 /**
Suprabh Shukla79000492018-12-24 17:03:02 -0800886 * Returns whether a package should be hidden from suggestions to the user. Currently, this
887 * could be done because the package was marked as distracting to the user via
888 * {@code PackageManager.setDistractingPackageRestrictions(String[], int)}.
889 *
890 * @param packageName The package for which to check.
891 * @param user the {@link UserHandle} of the profile.
892 * @return
893 */
894 public boolean shouldHideFromSuggestions(@NonNull String packageName,
895 @NonNull UserHandle user) {
Daulet Zhanguzina2044e12019-12-30 16:34:59 +0000896 Objects.requireNonNull(packageName, "packageName");
897 Objects.requireNonNull(user, "user");
Suprabh Shukla79000492018-12-24 17:03:02 -0800898 try {
899 return mService.shouldHideFromSuggestions(packageName, user);
900 } catch (RemoteException re) {
901 throw re.rethrowFromSystemServer();
902 }
903 }
904
905 /**
Benjamin Miller7afa84c2017-07-17 13:01:35 +0200906 * Returns {@link ApplicationInfo} about an application installed for a specific user profile.
Kenny Guy77242752016-01-15 13:29:06 +0000907 *
Amith Yamasani0d1fd8d2016-10-12 14:21:51 -0700908 * @param packageName The package name of the application
Kenny Guy77242752016-01-15 13:29:06 +0000909 * @param flags Additional option flags {@link PackageManager#getApplicationInfo}
910 * @param user The UserHandle of the profile.
911 *
Benjamin Miller7afa84c2017-07-17 13:01:35 +0200912 * @return {@link ApplicationInfo} containing information about the package. Returns
913 * {@code null} if the package isn't installed for the given profile, or the profile
914 * isn't enabled.
Kenny Guy77242752016-01-15 13:29:06 +0000915 */
Makoto Onuki7c7fbf62017-04-14 11:03:56 -0700916 public ApplicationInfo getApplicationInfo(@NonNull String packageName,
917 @ApplicationInfoFlags int flags, @NonNull UserHandle user)
918 throws PackageManager.NameNotFoundException {
Daulet Zhanguzina2044e12019-12-30 16:34:59 +0000919 Objects.requireNonNull(packageName, "packageName");
920 Objects.requireNonNull(user, "user");
Makoto Onukide3c16c2017-01-26 11:39:31 -0800921 logErrorForInvalidProfileAccess(user);
Kenny Guy77242752016-01-15 13:29:06 +0000922 try {
Makoto Onuki7c7fbf62017-04-14 11:03:56 -0700923 final ApplicationInfo ai = mService
924 .getApplicationInfo(mContext.getPackageName(), packageName, flags, user);
925 if (ai == null) {
926 throw new NameNotFoundException("Package " + packageName + " not found for user "
927 + user.getIdentifier());
928 }
929 return ai;
Kenny Guy77242752016-01-15 13:29:06 +0000930 } catch (RemoteException re) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700931 throw re.rethrowFromSystemServer();
Kenny Guy77242752016-01-15 13:29:06 +0000932 }
933 }
934
935 /**
Varun Shah2546cef2019-01-11 15:50:54 -0800936 * Returns an object describing the app usage limit for the given package.
937 * If there are multiple limits that apply to the package, the one with the smallest
938 * time remaining will be returned.
939 *
940 * @param packageName name of the package whose app usage limit will be returned
941 * @param user the user of the package
942 *
943 * @return an {@link AppUsageLimit} object describing the app time limit containing
944 * the given package with the smallest time remaining, or {@code null} if none exist.
Varun Shahe9abb752019-02-11 11:25:06 -0800945 * @throws SecurityException when the caller is not the recents app.
Sunny Goyalbeee1972019-03-29 11:38:16 -0700946 * @hide
Varun Shah2546cef2019-01-11 15:50:54 -0800947 */
948 @Nullable
Sunny Goyalbeee1972019-03-29 11:38:16 -0700949 @SystemApi
Varun Shah2c9263c2019-02-15 10:51:10 -0800950 public LauncherApps.AppUsageLimit getAppUsageLimit(@NonNull String packageName,
951 @NonNull UserHandle user) {
Varun Shah2546cef2019-01-11 15:50:54 -0800952 try {
953 return mService.getAppUsageLimit(mContext.getPackageName(), packageName, user);
954 } catch (RemoteException re) {
955 throw re.rethrowFromSystemServer();
956 }
957 }
958
959 /**
Kenny Guy53fa4ec2014-04-29 14:24:18 +0100960 * Checks if the activity exists and it enabled for a profile.
961 *
Makoto Onuki516020a2019-01-28 14:16:42 -0800962 * <p>The activity may still not be exported, in which case {@link #startMainActivity} will
963 * throw a {@link SecurityException} unless the caller has the same UID as the target app's.
964 *
Kenny Guy53fa4ec2014-04-29 14:24:18 +0100965 * @param component The activity to check.
966 * @param user The UserHandle of the profile.
967 *
968 * @return true if the activity exists and is enabled.
969 */
Kenny Guyf939dba2014-08-15 15:32:34 +0100970 public boolean isActivityEnabled(ComponentName component, UserHandle user) {
Makoto Onukide3c16c2017-01-26 11:39:31 -0800971 logErrorForInvalidProfileAccess(user);
Kenny Guy53fa4ec2014-04-29 14:24:18 +0100972 try {
Makoto Onuki3a2541e2017-01-24 09:00:15 -0800973 return mService.isActivityEnabled(mContext.getPackageName(), component, user);
Kenny Guy53fa4ec2014-04-29 14:24:18 +0100974 } catch (RemoteException re) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700975 throw re.rethrowFromSystemServer();
Kenny Guy53fa4ec2014-04-29 14:24:18 +0100976 }
977 }
978
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800979 /**
Dianne Hackbornc160fa42017-11-01 16:14:26 -0700980 * Returns whether the caller can access the shortcut information. Access is currently
981 * available to:
Makoto Onuki2d5b4652016-03-11 16:09:54 -0800982 *
Dianne Hackbornc160fa42017-11-01 16:14:26 -0700983 * <ul>
984 * <li>The current launcher (or default launcher if there is no set current launcher).</li>
985 * <li>The currently active voice interaction service.</li>
986 * </ul>
Makoto Onuki2d5b4652016-03-11 16:09:54 -0800987 *
Makoto Onuki4a910962016-07-07 13:57:34 -0700988 * <p>Note when this method returns {@code false}, it may be a temporary situation because
Makoto Onuki2d5b4652016-03-11 16:09:54 -0800989 * the user is trying a new launcher application. The user may decide to change the default
Makoto Onuki4a910962016-07-07 13:57:34 -0700990 * launcher back to the calling application again, so even if a launcher application loses
Makoto Onuki2d5b4652016-03-11 16:09:54 -0800991 * this permission, it does <b>not</b> have to purge pinned shortcut information.
Makoto Onukife9c9662016-07-25 15:12:23 -0700992 * If the calling launcher application contains pinned shortcuts, they will still work,
993 * even though the caller no longer has the shortcut host permission.
Makoto Onuki4a910962016-07-07 13:57:34 -0700994 *
Makoto Onuki02f338e2016-07-29 09:40:40 -0700995 * @throws IllegalStateException when the user is locked.
Makoto Onuki9c850012016-07-26 15:50:50 -0700996 *
Makoto Onuki4a910962016-07-07 13:57:34 -0700997 * @see ShortcutManager
Makoto Onuki2d5b4652016-03-11 16:09:54 -0800998 */
999 public boolean hasShortcutHostPermission() {
1000 try {
1001 return mService.hasShortcutHostPermission(mContext.getPackageName());
1002 } catch (RemoteException re) {
1003 throw re.rethrowFromSystemServer();
1004 }
1005 }
1006
Makoto Onukib1588c02017-10-12 15:11:45 -07001007 private List<ShortcutInfo> maybeUpdateDisabledMessage(List<ShortcutInfo> shortcuts) {
1008 if (shortcuts == null) {
1009 return null;
1010 }
1011 for (int i = shortcuts.size() - 1; i >= 0; i--) {
1012 final ShortcutInfo si = shortcuts.get(i);
1013 final String message = ShortcutInfo.getDisabledReasonForRestoreIssue(mContext,
1014 si.getDisabledReason());
1015 if (message != null) {
1016 si.setDisabledMessage(message);
1017 }
1018 }
1019 return shortcuts;
1020 }
1021
Makoto Onuki2d5b4652016-03-11 16:09:54 -08001022 /**
Makoto Onuki4a910962016-07-07 13:57:34 -07001023 * Returns {@link ShortcutInfo}s that match {@code query}.
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001024 *
Makoto Onuki2d5b4652016-03-11 16:09:54 -08001025 * <p>Callers must be allowed to access the shortcut information, as defined in {@link
1026 * #hasShortcutHostPermission()}.
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001027 *
1028 * @param query result includes shortcuts matching this query.
1029 * @param user The UserHandle of the profile.
1030 *
1031 * @return the IDs of {@link ShortcutInfo}s that match the query.
Makoto Onuki02f338e2016-07-29 09:40:40 -07001032 * @throws IllegalStateException when the user is locked, or when the {@code user} user
1033 * is locked or not running.
Makoto Onuki4a910962016-07-07 13:57:34 -07001034 *
1035 * @see ShortcutManager
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001036 */
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001037 @Nullable
1038 public List<ShortcutInfo> getShortcuts(@NonNull ShortcutQuery query,
1039 @NonNull UserHandle user) {
Makoto Onukide3c16c2017-01-26 11:39:31 -08001040 logErrorForInvalidProfileAccess(user);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001041 try {
Makoto Onukib1588c02017-10-12 15:11:45 -07001042 // Note this is the only case we need to update the disabled message for shortcuts
1043 // that weren't restored.
1044 // The restore problem messages are only shown by the user, and publishers will never
1045 // see them. The only other API that the launcher gets shortcuts is the shortcut
1046 // changed callback, but that only returns shortcuts with the "key" information, so
1047 // that won't return disabled message.
1048 return maybeUpdateDisabledMessage(mService.getShortcuts(mContext.getPackageName(),
Mehdi Alizadehae808ff2020-01-21 13:39:53 -08001049 query.mChangedSince, query.mPackage, query.mShortcutIds, query.mLocusIds,
1050 query.mActivity, query.mQueryFlags, user)
Makoto Onukib1588c02017-10-12 15:11:45 -07001051 .getList());
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001052 } catch (RemoteException e) {
1053 throw e.rethrowFromSystemServer();
1054 }
1055 }
1056
1057 /**
Makoto Onukiabe84422016-04-07 09:41:19 -07001058 * @hide // No longer used. Use getShortcuts() instead. Kept for unit tests.
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001059 */
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001060 @Nullable
Makoto Onukib5a012f2016-06-21 11:13:53 -07001061 @Deprecated
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001062 public List<ShortcutInfo> getShortcutInfo(@NonNull String packageName,
1063 @NonNull List<String> ids, @NonNull UserHandle user) {
Makoto Onukiabe84422016-04-07 09:41:19 -07001064 final ShortcutQuery q = new ShortcutQuery();
1065 q.setPackage(packageName);
1066 q.setShortcutIds(ids);
Makoto Onuki4d6b87f2016-06-17 13:47:40 -07001067 q.setQueryFlags(ShortcutQuery.FLAG_GET_ALL_KINDS);
Makoto Onukiabe84422016-04-07 09:41:19 -07001068 return getShortcuts(q, user);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001069 }
1070
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001071 /**
1072 * Pin shortcuts on a package.
1073 *
1074 * <p>This API is <b>NOT</b> cumulative; this will replace all pinned shortcuts for the package.
1075 * However, different launchers may have different set of pinned shortcuts.
1076 *
Makoto Onukife9c9662016-07-25 15:12:23 -07001077 * <p>The calling launcher application must be allowed to access the shortcut information,
1078 * as defined in {@link #hasShortcutHostPermission()}.
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001079 *
1080 * @param packageName The target package name.
1081 * @param shortcutIds The IDs of the shortcut to be pinned.
1082 * @param user The UserHandle of the profile.
Makoto Onuki02f338e2016-07-29 09:40:40 -07001083 * @throws IllegalStateException when the user is locked, or when the {@code user} user
1084 * is locked or not running.
Makoto Onuki4a910962016-07-07 13:57:34 -07001085 *
1086 * @see ShortcutManager
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001087 */
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001088 public void pinShortcuts(@NonNull String packageName, @NonNull List<String> shortcutIds,
1089 @NonNull UserHandle user) {
Makoto Onukide3c16c2017-01-26 11:39:31 -08001090 logErrorForInvalidProfileAccess(user);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001091 try {
1092 mService.pinShortcuts(mContext.getPackageName(), packageName, shortcutIds, user);
1093 } catch (RemoteException e) {
1094 throw e.rethrowFromSystemServer();
1095 }
1096 }
1097
1098 /**
Mehdi Alizadeh0de8c292020-01-21 17:27:26 -08001099 * Mark shortcuts as cached for a package.
1100 *
1101 * <p>Only dynamic long lived shortcuts can be cached. None dynamic or non long lived shortcuts
1102 * in the list will be ignored.
1103 *
1104 * <p>Unlike pinned shortcuts, where different callers can have different sets of pinned
1105 * shortcuts, cached state is per shortcut only, and even if multiple callers cache the same
1106 * shortcut, it can be uncached by any valid caller.
1107 *
1108 * @param packageName The target package name.
1109 * @param shortcutIds The IDs of the shortcut to be cached.
1110 * @param user The UserHandle of the profile.
1111 * @throws IllegalStateException when the user is locked, or when the {@code user} user
1112 * is locked or not running.
1113 *
1114 * @see ShortcutManager
1115 *
1116 * @hide
1117 */
1118 @RequiresPermission(android.Manifest.permission.ACCESS_SHORTCUTS)
1119 public void cacheShortcuts(@NonNull String packageName, @NonNull List<String> shortcutIds,
1120 @NonNull UserHandle user) {
1121 logErrorForInvalidProfileAccess(user);
1122 try {
1123 mService.cacheShortcuts(mContext.getPackageName(), packageName, shortcutIds, user);
1124 } catch (RemoteException e) {
1125 throw e.rethrowFromSystemServer();
1126 }
1127 }
1128
1129 /**
1130 * Remove cached flag from shortcuts for a package.
1131 *
1132 * @param packageName The target package name.
1133 * @param shortcutIds The IDs of the shortcut to be uncached.
1134 * @param user The UserHandle of the profile.
1135 * @throws IllegalStateException when the user is locked, or when the {@code user} user
1136 * is locked or not running.
1137 *
1138 * @see ShortcutManager
1139 *
1140 * @hide
1141 */
1142 @RequiresPermission(android.Manifest.permission.ACCESS_SHORTCUTS)
1143 public void uncacheShortcuts(@NonNull String packageName, @NonNull List<String> shortcutIds,
1144 @NonNull UserHandle user) {
1145 logErrorForInvalidProfileAccess(user);
1146 try {
1147 mService.uncacheShortcuts(mContext.getPackageName(), packageName, shortcutIds, user);
1148 } catch (RemoteException e) {
1149 throw e.rethrowFromSystemServer();
1150 }
1151 }
1152
1153 /**
Makoto Onukib6d35232016-04-04 15:57:17 -07001154 * @hide kept for testing.
Makoto Onukiabe84422016-04-07 09:41:19 -07001155 */
Makoto Onukib5a012f2016-06-21 11:13:53 -07001156 @Deprecated
Makoto Onukiabe84422016-04-07 09:41:19 -07001157 public int getShortcutIconResId(@NonNull ShortcutInfo shortcut) {
Makoto Onukib6d35232016-04-04 15:57:17 -07001158 return shortcut.getIconResourceId();
Makoto Onukiabe84422016-04-07 09:41:19 -07001159 }
1160
1161 /**
Makoto Onukib6d35232016-04-04 15:57:17 -07001162 * @hide kept for testing.
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001163 */
Makoto Onukib5a012f2016-06-21 11:13:53 -07001164 @Deprecated
Makoto Onukiabe84422016-04-07 09:41:19 -07001165 public int getShortcutIconResId(@NonNull String packageName, @NonNull String shortcutId,
1166 @NonNull UserHandle user) {
Makoto Onukib6d35232016-04-04 15:57:17 -07001167 final ShortcutQuery q = new ShortcutQuery();
1168 q.setPackage(packageName);
1169 q.setShortcutIds(Arrays.asList(shortcutId));
Makoto Onuki4d6b87f2016-06-17 13:47:40 -07001170 q.setQueryFlags(ShortcutQuery.FLAG_GET_ALL_KINDS);
Makoto Onukib6d35232016-04-04 15:57:17 -07001171 final List<ShortcutInfo> shortcuts = getShortcuts(q, user);
Makoto Onukiabe84422016-04-07 09:41:19 -07001172
Makoto Onukib6d35232016-04-04 15:57:17 -07001173 return shortcuts.size() > 0 ? shortcuts.get(0).getIconResourceId() : 0;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001174 }
1175
1176 /**
Makoto Onukib5a012f2016-06-21 11:13:53 -07001177 * @hide internal/unit tests only
Makoto Onukiabe84422016-04-07 09:41:19 -07001178 */
1179 public ParcelFileDescriptor getShortcutIconFd(
1180 @NonNull ShortcutInfo shortcut) {
Makoto Onuki22fcc682016-05-17 14:52:19 -07001181 return getShortcutIconFd(shortcut.getPackage(), shortcut.getId(),
Makoto Onukiabe84422016-04-07 09:41:19 -07001182 shortcut.getUserId());
1183 }
1184
1185 /**
Makoto Onukib5a012f2016-06-21 11:13:53 -07001186 * @hide internal/unit tests only
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001187 */
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001188 public ParcelFileDescriptor getShortcutIconFd(
Makoto Onukiabe84422016-04-07 09:41:19 -07001189 @NonNull String packageName, @NonNull String shortcutId, @NonNull UserHandle user) {
1190 return getShortcutIconFd(packageName, shortcutId, user.getIdentifier());
1191 }
1192
1193 private ParcelFileDescriptor getShortcutIconFd(
1194 @NonNull String packageName, @NonNull String shortcutId, int userId) {
Makoto Onuki55046222016-03-08 10:49:47 -08001195 try {
Makoto Onukiabe84422016-04-07 09:41:19 -07001196 return mService.getShortcutIconFd(mContext.getPackageName(),
1197 packageName, shortcutId, userId);
Makoto Onuki55046222016-03-08 10:49:47 -08001198 } catch (RemoteException e) {
1199 throw e.rethrowFromSystemServer();
1200 }
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001201 }
1202
Makoto Onuki04b9aab2016-05-23 17:13:30 -07001203 /**
1204 * Returns the icon for this shortcut, without any badging for the profile.
1205 *
Makoto Onukife9c9662016-07-25 15:12:23 -07001206 * <p>The calling launcher application must be allowed to access the shortcut information,
1207 * as defined in {@link #hasShortcutHostPermission()}.
Makoto Onuki4a910962016-07-07 13:57:34 -07001208 *
Makoto Onuki04b9aab2016-05-23 17:13:30 -07001209 * @param density The preferred density of the icon, zero for default density. Use
1210 * density DPI values from {@link DisplayMetrics}.
Makoto Onuki4a910962016-07-07 13:57:34 -07001211 *
1212 * @return The drawable associated with the shortcut.
Makoto Onuki02f338e2016-07-29 09:40:40 -07001213 * @throws IllegalStateException when the user is locked, or when the {@code user} user
1214 * is locked or not running.
Makoto Onuki4a910962016-07-07 13:57:34 -07001215 *
1216 * @see ShortcutManager
Makoto Onuki04b9aab2016-05-23 17:13:30 -07001217 * @see #getShortcutBadgedIconDrawable(ShortcutInfo, int)
1218 * @see DisplayMetrics
Makoto Onuki04b9aab2016-05-23 17:13:30 -07001219 */
1220 public Drawable getShortcutIconDrawable(@NonNull ShortcutInfo shortcut, int density) {
1221 if (shortcut.hasIconFile()) {
1222 final ParcelFileDescriptor pfd = getShortcutIconFd(shortcut);
1223 if (pfd == null) {
1224 return null;
1225 }
1226 try {
1227 final Bitmap bmp = BitmapFactory.decodeFileDescriptor(pfd.getFileDescriptor());
Hyunyoung Songf281e7a2017-02-13 10:57:42 -08001228 if (bmp != null) {
1229 BitmapDrawable dr = new BitmapDrawable(mContext.getResources(), bmp);
Hyunyoung Songe4179e22017-03-01 12:51:26 -08001230 if (shortcut.hasAdaptiveBitmap()) {
Hyunyoung Songbe8835e2017-02-17 11:25:08 -08001231 return new AdaptiveIconDrawable(null, dr);
Hyunyoung Songf281e7a2017-02-13 10:57:42 -08001232 } else {
1233 return dr;
1234 }
1235 }
1236 return null;
Makoto Onuki04b9aab2016-05-23 17:13:30 -07001237 } finally {
1238 try {
1239 pfd.close();
1240 } catch (IOException ignore) {
1241 }
1242 }
1243 } else if (shortcut.hasIconResource()) {
Makoto Onuki2d895c32016-12-02 15:48:40 -08001244 return loadDrawableResourceFromPackage(shortcut.getPackage(),
1245 shortcut.getIconResourceId(), shortcut.getUserHandle(), density);
1246 } else if (shortcut.getIcon() != null) {
1247 // This happens if a shortcut is pending-approval.
1248 final Icon icon = shortcut.getIcon();
1249 switch (icon.getType()) {
1250 case Icon.TYPE_RESOURCE: {
1251 return loadDrawableResourceFromPackage(shortcut.getPackage(),
1252 icon.getResId(), shortcut.getUserHandle(), density);
Makoto Onuki04b9aab2016-05-23 17:13:30 -07001253 }
Hyunyoung Songf281e7a2017-02-13 10:57:42 -08001254 case Icon.TYPE_BITMAP:
Hyunyoung Songe4179e22017-03-01 12:51:26 -08001255 case Icon.TYPE_ADAPTIVE_BITMAP: {
Makoto Onuki2d895c32016-12-02 15:48:40 -08001256 return icon.loadDrawable(mContext);
1257 }
1258 default:
1259 return null; // Shouldn't happen though.
Makoto Onuki04b9aab2016-05-23 17:13:30 -07001260 }
1261 } else {
1262 return null; // Has no icon.
1263 }
Makoto Onuki20c95f82016-05-11 16:51:01 -07001264 }
1265
Makoto Onuki2d895c32016-12-02 15:48:40 -08001266 private Drawable loadDrawableResourceFromPackage(String packageName, int resId,
1267 UserHandle user, int density) {
1268 try {
1269 if (resId == 0) {
1270 return null; // Shouldn't happen but just in case.
1271 }
1272 final ApplicationInfo ai = getApplicationInfo(packageName, /* flags =*/ 0, user);
1273 final Resources res = mContext.getPackageManager().getResourcesForApplication(ai);
1274 return res.getDrawableForDensity(resId, density);
1275 } catch (NameNotFoundException | Resources.NotFoundException e) {
1276 return null;
1277 }
1278 }
1279
Makoto Onuki04b9aab2016-05-23 17:13:30 -07001280 /**
1281 * Returns the shortcut icon with badging appropriate for the profile.
1282 *
Makoto Onukife9c9662016-07-25 15:12:23 -07001283 * <p>The calling launcher application must be allowed to access the shortcut information,
1284 * as defined in {@link #hasShortcutHostPermission()}.
Makoto Onuki4a910962016-07-07 13:57:34 -07001285 *
Makoto Onuki04b9aab2016-05-23 17:13:30 -07001286 * @param density Optional density for the icon, or 0 to use the default density. Use
Makoto Onuki04b9aab2016-05-23 17:13:30 -07001287 * @return A badged icon for the shortcut.
Makoto Onuki02f338e2016-07-29 09:40:40 -07001288 * @throws IllegalStateException when the user is locked, or when the {@code user} user
1289 * is locked or not running.
Makoto Onuki4a910962016-07-07 13:57:34 -07001290 *
1291 * @see ShortcutManager
Makoto Onukife9c9662016-07-25 15:12:23 -07001292 * @see #getShortcutIconDrawable(ShortcutInfo, int)
Makoto Onuki4a910962016-07-07 13:57:34 -07001293 * @see DisplayMetrics
Makoto Onuki04b9aab2016-05-23 17:13:30 -07001294 */
1295 public Drawable getShortcutBadgedIconDrawable(ShortcutInfo shortcut, int density) {
1296 final Drawable originalIcon = getShortcutIconDrawable(shortcut, density);
1297
1298 return (originalIcon == null) ? null : mContext.getPackageManager().getUserBadgedIcon(
1299 originalIcon, shortcut.getUserHandle());
Makoto Onuki20c95f82016-05-11 16:51:01 -07001300 }
1301
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001302 /**
Makoto Onuki4a910962016-07-07 13:57:34 -07001303 * Starts a shortcut.
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001304 *
Makoto Onukife9c9662016-07-25 15:12:23 -07001305 * <p>The calling launcher application must be allowed to access the shortcut information,
1306 * as defined in {@link #hasShortcutHostPermission()}.
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001307 *
Makoto Onuki43204b82016-03-08 16:16:44 -08001308 * @param packageName The target shortcut package name.
1309 * @param shortcutId The target shortcut ID.
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001310 * @param sourceBounds The Rect containing the source bounds of the clicked icon.
1311 * @param startActivityOptions Options to pass to startActivity.
1312 * @param user The UserHandle of the profile.
Makoto Onuki02f338e2016-07-29 09:40:40 -07001313 * @throws IllegalStateException when the user is locked, or when the {@code user} user
1314 * is locked or not running.
Makoto Onuki83f6d2d2016-07-11 14:30:19 -07001315 *
1316 * @throws android.content.ActivityNotFoundException failed to start shortcut. (e.g.
1317 * the shortcut no longer exists, is disabled, the intent receiver activity doesn't exist, etc)
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001318 */
Makoto Onukid6880792016-06-29 13:37:43 -07001319 public void startShortcut(@NonNull String packageName, @NonNull String shortcutId,
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001320 @Nullable Rect sourceBounds, @Nullable Bundle startActivityOptions,
1321 @NonNull UserHandle user) {
Makoto Onukide3c16c2017-01-26 11:39:31 -08001322 logErrorForInvalidProfileAccess(user);
1323
Makoto Onukid6880792016-06-29 13:37:43 -07001324 startShortcut(packageName, shortcutId, sourceBounds, startActivityOptions,
Makoto Onukiabe84422016-04-07 09:41:19 -07001325 user.getIdentifier());
1326 }
1327
1328 /**
1329 * Launches a shortcut.
1330 *
Makoto Onukife9c9662016-07-25 15:12:23 -07001331 * <p>The calling launcher application must be allowed to access the shortcut information,
1332 * as defined in {@link #hasShortcutHostPermission()}.
Makoto Onukiabe84422016-04-07 09:41:19 -07001333 *
1334 * @param shortcut The target shortcut.
1335 * @param sourceBounds The Rect containing the source bounds of the clicked icon.
1336 * @param startActivityOptions Options to pass to startActivity.
Makoto Onuki02f338e2016-07-29 09:40:40 -07001337 * @throws IllegalStateException when the user is locked, or when the {@code user} user
1338 * is locked or not running.
Makoto Onuki83f6d2d2016-07-11 14:30:19 -07001339 *
1340 * @throws android.content.ActivityNotFoundException failed to start shortcut. (e.g.
1341 * the shortcut no longer exists, is disabled, the intent receiver activity doesn't exist, etc)
Makoto Onukiabe84422016-04-07 09:41:19 -07001342 */
Makoto Onukid6880792016-06-29 13:37:43 -07001343 public void startShortcut(@NonNull ShortcutInfo shortcut,
Makoto Onukiabe84422016-04-07 09:41:19 -07001344 @Nullable Rect sourceBounds, @Nullable Bundle startActivityOptions) {
Makoto Onukid6880792016-06-29 13:37:43 -07001345 startShortcut(shortcut.getPackage(), shortcut.getId(),
Makoto Onukiabe84422016-04-07 09:41:19 -07001346 sourceBounds, startActivityOptions,
1347 shortcut.getUserId());
1348 }
1349
Mathew Inwood5c0d3542018-08-14 13:54:31 +01001350 @UnsupportedAppUsage
Makoto Onukid6880792016-06-29 13:37:43 -07001351 private void startShortcut(@NonNull String packageName, @NonNull String shortcutId,
Makoto Onukiabe84422016-04-07 09:41:19 -07001352 @Nullable Rect sourceBounds, @Nullable Bundle startActivityOptions,
1353 int userId) {
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001354 try {
Philip P. Moltmannee295092020-02-10 08:46:26 -08001355 final boolean success = mService.startShortcut(mContext.getPackageName(), packageName,
1356 null /* default featureId */, shortcutId, sourceBounds, startActivityOptions,
1357 userId);
Makoto Onuki83f6d2d2016-07-11 14:30:19 -07001358 if (!success) {
1359 throw new ActivityNotFoundException("Shortcut could not be started");
1360 }
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001361 } catch (RemoteException e) {
1362 throw e.rethrowFromSystemServer();
1363 }
1364 }
Kenny Guy53fa4ec2014-04-29 14:24:18 +01001365
1366 /**
Jon Miranda2b340a22019-01-25 14:03:49 -08001367 * Registers a callback for changes to packages in this user and managed profiles.
Kenny Guyc01545372014-06-16 14:17:26 +01001368 *
Kenny Guy10a574f2014-08-26 16:17:58 +01001369 * @param callback The callback to register.
Kenny Guyc01545372014-06-16 14:17:26 +01001370 */
Kenny Guy10a574f2014-08-26 16:17:58 +01001371 public void registerCallback(Callback callback) {
1372 registerCallback(callback, null);
Kenny Guyb42c89b2014-07-28 19:20:07 +01001373 }
1374
1375 /**
Jon Miranda2b340a22019-01-25 14:03:49 -08001376 * Registers a callback for changes to packages in this user and managed profiles.
Kenny Guyb42c89b2014-07-28 19:20:07 +01001377 *
Kenny Guy10a574f2014-08-26 16:17:58 +01001378 * @param callback The callback to register.
Kenny Guyb42c89b2014-07-28 19:20:07 +01001379 * @param handler that should be used to post callbacks on, may be null.
1380 */
Kenny Guy10a574f2014-08-26 16:17:58 +01001381 public void registerCallback(Callback callback, Handler handler) {
Kenny Guyc01545372014-06-16 14:17:26 +01001382 synchronized (this) {
Kenny Guy172a2162015-06-19 17:21:28 +01001383 if (callback != null && findCallbackLocked(callback) < 0) {
Kenny Guyb42c89b2014-07-28 19:20:07 +01001384 boolean addedFirstCallback = mCallbacks.size() == 0;
1385 addCallbackLocked(callback, handler);
1386 if (addedFirstCallback) {
Kenny Guyc01545372014-06-16 14:17:26 +01001387 try {
Makoto Onuki4dbe0de2016-03-14 17:31:49 -07001388 mService.addOnAppsChangedListener(mContext.getPackageName(),
1389 mAppsChangedListener);
Kenny Guyc01545372014-06-16 14:17:26 +01001390 } catch (RemoteException re) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001391 throw re.rethrowFromSystemServer();
Kenny Guyc01545372014-06-16 14:17:26 +01001392 }
1393 }
1394 }
1395 }
1396 }
1397
1398 /**
Kenny Guy10a574f2014-08-26 16:17:58 +01001399 * Unregisters a callback that was previously registered.
Kenny Guyc01545372014-06-16 14:17:26 +01001400 *
Kenny Guy10a574f2014-08-26 16:17:58 +01001401 * @param callback The callback to unregister.
1402 * @see #registerCallback(Callback)
Kenny Guyc01545372014-06-16 14:17:26 +01001403 */
Kenny Guy10a574f2014-08-26 16:17:58 +01001404 public void unregisterCallback(Callback callback) {
Kenny Guyc01545372014-06-16 14:17:26 +01001405 synchronized (this) {
Kenny Guyb42c89b2014-07-28 19:20:07 +01001406 removeCallbackLocked(callback);
Kenny Guy44b6dee2014-07-10 18:10:14 +01001407 if (mCallbacks.size() == 0) {
Amith Yamasanie781c812014-05-28 15:28:18 -07001408 try {
1409 mService.removeOnAppsChangedListener(mAppsChangedListener);
1410 } catch (RemoteException re) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001411 throw re.rethrowFromSystemServer();
Amith Yamasanie781c812014-05-28 15:28:18 -07001412 }
Amith Yamasani4f582632014-02-19 14:31:52 -08001413 }
1414 }
1415 }
1416
Kenny Guy172a2162015-06-19 17:21:28 +01001417 /** @return position in mCallbacks for callback or -1 if not present. */
1418 private int findCallbackLocked(Callback callback) {
Kenny Guyb42c89b2014-07-28 19:20:07 +01001419 if (callback == null) {
1420 throw new IllegalArgumentException("Callback cannot be null");
1421 }
1422 final int size = mCallbacks.size();
1423 for (int i = 0; i < size; ++i) {
1424 if (mCallbacks.get(i).mCallback == callback) {
Kenny Guy172a2162015-06-19 17:21:28 +01001425 return i;
Kenny Guyb42c89b2014-07-28 19:20:07 +01001426 }
1427 }
Kenny Guy172a2162015-06-19 17:21:28 +01001428 return -1;
1429 }
1430
1431 private void removeCallbackLocked(Callback callback) {
1432 int pos = findCallbackLocked(callback);
1433 if (pos >= 0) {
1434 mCallbacks.remove(pos);
1435 }
Kenny Guyb42c89b2014-07-28 19:20:07 +01001436 }
1437
Kenny Guyf939dba2014-08-15 15:32:34 +01001438 private void addCallbackLocked(Callback callback, Handler handler) {
Kenny Guyb42c89b2014-07-28 19:20:07 +01001439 // Remove if already present.
1440 removeCallbackLocked(callback);
1441 if (handler == null) {
1442 handler = new Handler();
1443 }
1444 CallbackMessageHandler toAdd = new CallbackMessageHandler(handler.getLooper(), callback);
1445 mCallbacks.add(toAdd);
1446 }
1447
Amith Yamasani4f582632014-02-19 14:31:52 -08001448 private IOnAppsChangedListener.Stub mAppsChangedListener = new IOnAppsChangedListener.Stub() {
1449
1450 @Override
Kenny Guyb42c89b2014-07-28 19:20:07 +01001451 public void onPackageRemoved(UserHandle user, String packageName)
1452 throws RemoteException {
Amith Yamasani4f582632014-02-19 14:31:52 -08001453 if (DEBUG) {
1454 Log.d(TAG, "onPackageRemoved " + user.getIdentifier() + "," + packageName);
1455 }
1456 synchronized (LauncherApps.this) {
Kenny Guyb42c89b2014-07-28 19:20:07 +01001457 for (CallbackMessageHandler callback : mCallbacks) {
1458 callback.postOnPackageRemoved(packageName, user);
Kenny Guyc01545372014-06-16 14:17:26 +01001459 }
Amith Yamasani4f582632014-02-19 14:31:52 -08001460 }
1461 }
1462
1463 @Override
1464 public void onPackageChanged(UserHandle user, String packageName) throws RemoteException {
1465 if (DEBUG) {
1466 Log.d(TAG, "onPackageChanged " + user.getIdentifier() + "," + packageName);
1467 }
1468 synchronized (LauncherApps.this) {
Kenny Guyb42c89b2014-07-28 19:20:07 +01001469 for (CallbackMessageHandler callback : mCallbacks) {
1470 callback.postOnPackageChanged(packageName, user);
Kenny Guyc01545372014-06-16 14:17:26 +01001471 }
Amith Yamasani4f582632014-02-19 14:31:52 -08001472 }
1473 }
1474
1475 @Override
1476 public void onPackageAdded(UserHandle user, String packageName) throws RemoteException {
1477 if (DEBUG) {
1478 Log.d(TAG, "onPackageAdded " + user.getIdentifier() + "," + packageName);
1479 }
1480 synchronized (LauncherApps.this) {
Kenny Guyb42c89b2014-07-28 19:20:07 +01001481 for (CallbackMessageHandler callback : mCallbacks) {
1482 callback.postOnPackageAdded(packageName, user);
Kenny Guyc01545372014-06-16 14:17:26 +01001483 }
Amith Yamasani4f582632014-02-19 14:31:52 -08001484 }
1485 }
1486
1487 @Override
1488 public void onPackagesAvailable(UserHandle user, String[] packageNames, boolean replacing)
1489 throws RemoteException {
1490 if (DEBUG) {
1491 Log.d(TAG, "onPackagesAvailable " + user.getIdentifier() + "," + packageNames);
1492 }
1493 synchronized (LauncherApps.this) {
Kenny Guyb42c89b2014-07-28 19:20:07 +01001494 for (CallbackMessageHandler callback : mCallbacks) {
1495 callback.postOnPackagesAvailable(packageNames, user, replacing);
Kenny Guyc01545372014-06-16 14:17:26 +01001496 }
Amith Yamasani4f582632014-02-19 14:31:52 -08001497 }
1498 }
1499
1500 @Override
1501 public void onPackagesUnavailable(UserHandle user, String[] packageNames, boolean replacing)
1502 throws RemoteException {
1503 if (DEBUG) {
1504 Log.d(TAG, "onPackagesUnavailable " + user.getIdentifier() + "," + packageNames);
1505 }
1506 synchronized (LauncherApps.this) {
Kenny Guyb42c89b2014-07-28 19:20:07 +01001507 for (CallbackMessageHandler callback : mCallbacks) {
1508 callback.postOnPackagesUnavailable(packageNames, user, replacing);
Kenny Guyc01545372014-06-16 14:17:26 +01001509 }
Kenny Guy77242752016-01-15 13:29:06 +00001510 }
1511 }
1512
1513 @Override
Suprabh Shukla19b41f32018-03-26 22:35:13 -07001514 public void onPackagesSuspended(UserHandle user, String[] packageNames,
1515 Bundle launcherExtras)
Kenny Guy77242752016-01-15 13:29:06 +00001516 throws RemoteException {
1517 if (DEBUG) {
1518 Log.d(TAG, "onPackagesSuspended " + user.getIdentifier() + "," + packageNames);
1519 }
1520 synchronized (LauncherApps.this) {
1521 for (CallbackMessageHandler callback : mCallbacks) {
Suprabh Shukla19b41f32018-03-26 22:35:13 -07001522 callback.postOnPackagesSuspended(packageNames, launcherExtras, user);
Kenny Guy77242752016-01-15 13:29:06 +00001523 }
1524 }
1525 }
1526
1527 @Override
1528 public void onPackagesUnsuspended(UserHandle user, String[] packageNames)
1529 throws RemoteException {
1530 if (DEBUG) {
1531 Log.d(TAG, "onPackagesUnsuspended " + user.getIdentifier() + "," + packageNames);
1532 }
1533 synchronized (LauncherApps.this) {
1534 for (CallbackMessageHandler callback : mCallbacks) {
1535 callback.postOnPackagesUnsuspended(packageNames, user);
1536 }
1537 }
Amith Yamasani4f582632014-02-19 14:31:52 -08001538 }
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001539
1540 @Override
1541 public void onShortcutChanged(UserHandle user, String packageName,
1542 ParceledListSlice shortcuts) {
1543 if (DEBUG) {
1544 Log.d(TAG, "onShortcutChanged " + user.getIdentifier() + "," + packageName);
1545 }
1546 final List<ShortcutInfo> list = shortcuts.getList();
1547 synchronized (LauncherApps.this) {
1548 for (CallbackMessageHandler callback : mCallbacks) {
1549 callback.postOnShortcutChanged(packageName, user, list);
1550 }
1551 }
1552 }
Amith Yamasani4f582632014-02-19 14:31:52 -08001553 };
Kenny Guyb42c89b2014-07-28 19:20:07 +01001554
1555 private static class CallbackMessageHandler extends Handler {
1556 private static final int MSG_ADDED = 1;
1557 private static final int MSG_REMOVED = 2;
1558 private static final int MSG_CHANGED = 3;
1559 private static final int MSG_AVAILABLE = 4;
1560 private static final int MSG_UNAVAILABLE = 5;
Kenny Guy77242752016-01-15 13:29:06 +00001561 private static final int MSG_SUSPENDED = 6;
1562 private static final int MSG_UNSUSPENDED = 7;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001563 private static final int MSG_SHORTCUT_CHANGED = 8;
Kenny Guyb42c89b2014-07-28 19:20:07 +01001564
Kenny Guyf939dba2014-08-15 15:32:34 +01001565 private LauncherApps.Callback mCallback;
Kenny Guyb42c89b2014-07-28 19:20:07 +01001566
1567 private static class CallbackInfo {
1568 String[] packageNames;
1569 String packageName;
Suprabh Shukla19b41f32018-03-26 22:35:13 -07001570 Bundle launcherExtras;
Kenny Guyb42c89b2014-07-28 19:20:07 +01001571 boolean replacing;
1572 UserHandle user;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001573 List<ShortcutInfo> shortcuts;
Kenny Guyb42c89b2014-07-28 19:20:07 +01001574 }
1575
Kenny Guyf939dba2014-08-15 15:32:34 +01001576 public CallbackMessageHandler(Looper looper, LauncherApps.Callback callback) {
Kenny Guyb42c89b2014-07-28 19:20:07 +01001577 super(looper, null, true);
1578 mCallback = callback;
1579 }
1580
1581 @Override
1582 public void handleMessage(Message msg) {
1583 if (mCallback == null || !(msg.obj instanceof CallbackInfo)) {
1584 return;
1585 }
1586 CallbackInfo info = (CallbackInfo) msg.obj;
1587 switch (msg.what) {
1588 case MSG_ADDED:
1589 mCallback.onPackageAdded(info.packageName, info.user);
1590 break;
1591 case MSG_REMOVED:
1592 mCallback.onPackageRemoved(info.packageName, info.user);
1593 break;
1594 case MSG_CHANGED:
1595 mCallback.onPackageChanged(info.packageName, info.user);
1596 break;
1597 case MSG_AVAILABLE:
1598 mCallback.onPackagesAvailable(info.packageNames, info.user, info.replacing);
1599 break;
1600 case MSG_UNAVAILABLE:
1601 mCallback.onPackagesUnavailable(info.packageNames, info.user, info.replacing);
1602 break;
Kenny Guy77242752016-01-15 13:29:06 +00001603 case MSG_SUSPENDED:
Suprabh Shukla96212bc2018-04-10 15:04:51 -07001604 mCallback.onPackagesSuspended(info.packageNames, info.user, info.launcherExtras
1605 );
Kenny Guy77242752016-01-15 13:29:06 +00001606 break;
1607 case MSG_UNSUSPENDED:
1608 mCallback.onPackagesUnsuspended(info.packageNames, info.user);
1609 break;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001610 case MSG_SHORTCUT_CHANGED:
1611 mCallback.onShortcutsChanged(info.packageName, info.shortcuts, info.user);
1612 break;
Kenny Guyb42c89b2014-07-28 19:20:07 +01001613 }
1614 }
1615
1616 public void postOnPackageAdded(String packageName, UserHandle user) {
1617 CallbackInfo info = new CallbackInfo();
1618 info.packageName = packageName;
1619 info.user = user;
1620 obtainMessage(MSG_ADDED, info).sendToTarget();
1621 }
1622
1623 public void postOnPackageRemoved(String packageName, UserHandle user) {
1624 CallbackInfo info = new CallbackInfo();
1625 info.packageName = packageName;
1626 info.user = user;
1627 obtainMessage(MSG_REMOVED, info).sendToTarget();
1628 }
1629
1630 public void postOnPackageChanged(String packageName, UserHandle user) {
1631 CallbackInfo info = new CallbackInfo();
1632 info.packageName = packageName;
1633 info.user = user;
1634 obtainMessage(MSG_CHANGED, info).sendToTarget();
1635 }
1636
1637 public void postOnPackagesAvailable(String[] packageNames, UserHandle user,
1638 boolean replacing) {
1639 CallbackInfo info = new CallbackInfo();
1640 info.packageNames = packageNames;
1641 info.replacing = replacing;
1642 info.user = user;
1643 obtainMessage(MSG_AVAILABLE, info).sendToTarget();
1644 }
1645
1646 public void postOnPackagesUnavailable(String[] packageNames, UserHandle user,
1647 boolean replacing) {
1648 CallbackInfo info = new CallbackInfo();
1649 info.packageNames = packageNames;
1650 info.replacing = replacing;
1651 info.user = user;
1652 obtainMessage(MSG_UNAVAILABLE, info).sendToTarget();
1653 }
Kenny Guy77242752016-01-15 13:29:06 +00001654
Suprabh Shukla19b41f32018-03-26 22:35:13 -07001655 public void postOnPackagesSuspended(String[] packageNames, Bundle launcherExtras,
1656 UserHandle user) {
Kenny Guy77242752016-01-15 13:29:06 +00001657 CallbackInfo info = new CallbackInfo();
1658 info.packageNames = packageNames;
1659 info.user = user;
Suprabh Shukla19b41f32018-03-26 22:35:13 -07001660 info.launcherExtras = launcherExtras;
Kenny Guy77242752016-01-15 13:29:06 +00001661 obtainMessage(MSG_SUSPENDED, info).sendToTarget();
1662 }
1663
1664 public void postOnPackagesUnsuspended(String[] packageNames, UserHandle user) {
1665 CallbackInfo info = new CallbackInfo();
1666 info.packageNames = packageNames;
1667 info.user = user;
1668 obtainMessage(MSG_UNSUSPENDED, info).sendToTarget();
1669 }
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001670
1671 public void postOnShortcutChanged(String packageName, UserHandle user,
1672 List<ShortcutInfo> shortcuts) {
1673 CallbackInfo info = new CallbackInfo();
1674 info.packageName = packageName;
1675 info.user = user;
1676 info.shortcuts = shortcuts;
1677 obtainMessage(MSG_SHORTCUT_CHANGED, info).sendToTarget();
1678 }
Kenny Guyb42c89b2014-07-28 19:20:07 +01001679 }
Makoto Onuki2d895c32016-12-02 15:48:40 -08001680
1681 /**
Jon Miranda2b340a22019-01-25 14:03:49 -08001682 * Register a callback to watch for session lifecycle events in this user and managed profiles.
1683 * @param callback The callback to register.
1684 * @param executor {@link Executor} to handle the callbacks, cannot be null.
1685 *
1686 * @see PackageInstaller#registerSessionCallback(SessionCallback)
1687 */
1688 public void registerPackageInstallerSessionCallback(
1689 @NonNull @CallbackExecutor Executor executor, @NonNull SessionCallback callback) {
1690 if (executor == null) {
1691 throw new NullPointerException("Executor must not be null");
1692 }
1693
1694 synchronized (mDelegates) {
1695 final SessionCallbackDelegate delegate = new SessionCallbackDelegate(callback,
1696 executor);
1697 try {
1698 mService.registerPackageInstallerCallback(mContext.getPackageName(),
1699 delegate);
1700 } catch (RemoteException e) {
1701 throw e.rethrowFromSystemServer();
1702 }
1703 mDelegates.add(delegate);
1704 }
1705 }
1706
1707 /**
1708 * Unregisters a callback that was previously registered.
1709 *
1710 * @param callback The callback to unregister.
1711 * @see #registerPackageInstallerSessionCallback(Executor, SessionCallback)
1712 */
Jon Miranda93505982019-03-08 09:33:42 -08001713 public void unregisterPackageInstallerSessionCallback(@NonNull SessionCallback callback) {
Jon Miranda2b340a22019-01-25 14:03:49 -08001714 synchronized (mDelegates) {
1715 for (Iterator<SessionCallbackDelegate> i = mDelegates.iterator(); i.hasNext();) {
1716 final SessionCallbackDelegate delegate = i.next();
1717 if (delegate.mCallback == callback) {
1718 mPm.getPackageInstaller().unregisterSessionCallback(delegate.mCallback);
1719 i.remove();
1720 }
1721 }
1722 }
1723 }
1724
1725 /**
1726 * Return list of all known install sessions in this user and managed profiles, regardless
1727 * of the installer.
1728 *
1729 * @see PackageInstaller#getAllSessions()
1730 */
1731 public @NonNull List<SessionInfo> getAllPackageInstallerSessions() {
1732 try {
1733 return mService.getAllSessions(mContext.getPackageName()).getList();
1734 } catch (RemoteException e) {
1735 throw e.rethrowFromSystemServer();
1736 }
1737 }
1738
1739 /**
Mehdi Alizadeh9f680192020-01-16 18:09:24 -08001740 * Register a callback to watch for shortcut change events in this user and managed profiles.
1741 *
1742 * @param callback The callback to register.
1743 * @param query {@link ShortcutQuery} to match and filter the shortcut events. Only matching
1744 * shortcuts will be returned by the callback.
1745 * @param executor {@link Executor} to handle the callbacks. To dispatch callbacks to the main
1746 * thread of your application, you can use {@link android.content.Context#getMainExecutor()}.
1747 *
1748 * @hide
1749 */
1750 public void registerShortcutChangeCallback(@NonNull ShortcutChangeCallback callback,
1751 @NonNull ShortcutQuery query, @NonNull @CallbackExecutor Executor executor) {
1752 Objects.requireNonNull(callback, "Callback cannot be null");
1753 Objects.requireNonNull(query, "Query cannot be null");
1754 Objects.requireNonNull(executor, "Executor cannot be null");
1755
1756 synchronized (mShortcutChangeCallbacks) {
Mehdi Alizadehb754b7a2020-02-13 20:54:43 -08001757 IShortcutChangeCallback proxy = new ShortcutChangeCallbackProxy(executor, callback);
1758 mShortcutChangeCallbacks.put(callback, new Pair<>(executor, proxy));
Mehdi Alizadeh9f680192020-01-16 18:09:24 -08001759 try {
1760 mService.registerShortcutChangeCallback(mContext.getPackageName(),
Mehdi Alizadehae808ff2020-01-21 13:39:53 -08001761 query.mChangedSince, query.mPackage, query.mShortcutIds, query.mLocusIds,
Mehdi Alizadehb754b7a2020-02-13 20:54:43 -08001762 query.mActivity, query.mQueryFlags, proxy);
Mehdi Alizadeh9f680192020-01-16 18:09:24 -08001763 } catch (RemoteException e) {
1764 throw e.rethrowFromSystemServer();
1765 }
1766 }
1767 }
1768
1769 /**
1770 * Unregisters a callback that was previously registered.
1771 * @see #registerShortcutChangeCallback(ShortcutChangeCallback, ShortcutQuery, Executor)
1772 *
1773 * @param callback Callback to be unregistered.
1774 *
1775 * @hide
1776 */
1777 public void unregisterShortcutChangeCallback(@NonNull ShortcutChangeCallback callback) {
1778 Objects.requireNonNull(callback, "Callback cannot be null");
1779
1780 synchronized (mShortcutChangeCallbacks) {
Mehdi Alizadehb754b7a2020-02-13 20:54:43 -08001781 if (mShortcutChangeCallbacks.containsKey(callback)) {
1782 IShortcutChangeCallback proxy = mShortcutChangeCallbacks.remove(callback).second;
Mehdi Alizadeh9f680192020-01-16 18:09:24 -08001783 try {
Mehdi Alizadehb754b7a2020-02-13 20:54:43 -08001784 mService.unregisterShortcutChangeCallback(mContext.getPackageName(), proxy);
Mehdi Alizadeh9f680192020-01-16 18:09:24 -08001785 } catch (RemoteException e) {
1786 throw e.rethrowFromSystemServer();
1787 }
1788 }
1789 }
1790 }
1791
1792 /**
Makoto Onuki2d895c32016-12-02 15:48:40 -08001793 * A helper method to extract a {@link PinItemRequest} set to
1794 * the {@link #EXTRA_PIN_ITEM_REQUEST} extra.
1795 */
1796 public PinItemRequest getPinItemRequest(Intent intent) {
1797 return intent.getParcelableExtra(EXTRA_PIN_ITEM_REQUEST);
1798 }
1799
1800 /**
Sunny Goyal7f7372a2017-01-24 11:53:54 -08001801 * Represents a "pin shortcut" or a "pin appwidget" request made by an app, which is sent with
1802 * an {@link #ACTION_CONFIRM_PIN_SHORTCUT} or {@link #ACTION_CONFIRM_PIN_APPWIDGET} intent
1803 * respectively to the default launcher app.
Makoto Onuki2d895c32016-12-02 15:48:40 -08001804 *
Makoto Onukia37ac3d2017-04-14 12:33:10 -07001805 * <h3>Request of the {@link #REQUEST_TYPE_SHORTCUT} type.
Makoto Onuki0c280712017-01-19 15:14:27 -08001806 *
Makoto Onukia37ac3d2017-04-14 12:33:10 -07001807 * <p>A {@link #REQUEST_TYPE_SHORTCUT} request represents a request to pin a
1808 * {@link ShortcutInfo}. If the launcher accepts a request, call {@link #accept()},
1809 * or {@link #accept(Bundle)} with a null or empty Bundle. No options are defined for
1810 * pin-shortcuts requests.
1811 *
1812 * <p>{@link #getShortcutInfo()} always returns a non-null {@link ShortcutInfo} for this type.
1813 *
1814 * <p>The launcher may receive a request with a {@link ShortcutInfo} that is already pinned, in
1815 * which case {@link ShortcutInfo#isPinned()} returns true. This means the user wants to create
1816 * another pinned shortcut for a shortcut that's already pinned. If the launcher accepts it,
1817 * {@link #accept()} must still be called even though the shortcut is already pinned, and
1818 * create a new pinned shortcut icon for it.
1819 *
1820 * <p>See also {@link ShortcutManager} for more details.
1821 *
1822 * <h3>Request of the {@link #REQUEST_TYPE_APPWIDGET} type.
1823 *
1824 * <p>A {@link #REQUEST_TYPE_SHORTCUT} request represents a request to pin a
1825 * an AppWidget. If the launcher accepts a request, call {@link #accept(Bundle)} with
1826 * the appwidget integer ID set to the
1827 * {@link android.appwidget.AppWidgetManager#EXTRA_APPWIDGET_ID} extra.
1828 *
1829 * <p>{@link #getAppWidgetProviderInfo(Context)} always returns a non-null
1830 * {@link AppWidgetProviderInfo} for this type.
1831 *
1832 * <p>See also {@link AppWidgetManager} for more details.
Sunny Goyal7f7372a2017-01-24 11:53:54 -08001833 *
Makoto Onuki2d895c32016-12-02 15:48:40 -08001834 * @see #EXTRA_PIN_ITEM_REQUEST
1835 * @see #getPinItemRequest(Intent)
1836 */
1837 public static final class PinItemRequest implements Parcelable {
1838
1839 /** This is a request to pin shortcut. */
1840 public static final int REQUEST_TYPE_SHORTCUT = 1;
1841
Sunny Goyal87a563e2017-01-01 19:42:45 -08001842 /** This is a request to pin app widget. */
1843 public static final int REQUEST_TYPE_APPWIDGET = 2;
1844
Makoto Onukif5663b12017-01-09 14:09:56 -08001845 /** @hide */
Jeff Sharkeyce8db992017-12-13 20:05:05 -07001846 @IntDef(prefix = { "REQUEST_TYPE_" }, value = {
1847 REQUEST_TYPE_SHORTCUT,
1848 REQUEST_TYPE_APPWIDGET
1849 })
Makoto Onuki2d895c32016-12-02 15:48:40 -08001850 @Retention(RetentionPolicy.SOURCE)
1851 public @interface RequestType {}
1852
1853 private final int mRequestType;
Makoto Onuki2d895c32016-12-02 15:48:40 -08001854 private final IPinItemRequest mInner;
1855
1856 /**
1857 * @hide
1858 */
Makoto Onuki8abba3a2017-02-24 11:34:54 -08001859 public PinItemRequest(IPinItemRequest inner, int type) {
Sunny Goyal87a563e2017-01-01 19:42:45 -08001860 mInner = inner;
Makoto Onuki8abba3a2017-02-24 11:34:54 -08001861 mRequestType = type;
Makoto Onuki2d895c32016-12-02 15:48:40 -08001862 }
1863
1864 /**
Makoto Onukia37ac3d2017-04-14 12:33:10 -07001865 * Represents the type of a request, which is one of the {@code REQUEST_TYPE_} constants.
1866 *
1867 * @return one of the {@code REQUEST_TYPE_} constants.
Makoto Onuki2d895c32016-12-02 15:48:40 -08001868 */
1869 @RequestType
1870 public int getRequestType() {
1871 return mRequestType;
1872 }
1873
1874 /**
Makoto Onukia37ac3d2017-04-14 12:33:10 -07001875 * {@link ShortcutInfo} sent by the requesting app.
1876 * Always non-null for a {@link #REQUEST_TYPE_SHORTCUT} request, and always null for a
1877 * different request type.
1878 *
1879 * @return requested {@link ShortcutInfo} when a request is of the
1880 * {@link #REQUEST_TYPE_SHORTCUT} type. Null otherwise.
Makoto Onuki2d895c32016-12-02 15:48:40 -08001881 */
1882 @Nullable
1883 public ShortcutInfo getShortcutInfo() {
Makoto Onuki8abba3a2017-02-24 11:34:54 -08001884 try {
1885 return mInner.getShortcutInfo();
1886 } catch (RemoteException e) {
1887 throw e.rethrowAsRuntimeException();
1888 }
Makoto Onuki2d895c32016-12-02 15:48:40 -08001889 }
1890
1891 /**
Makoto Onukia37ac3d2017-04-14 12:33:10 -07001892 * {@link AppWidgetProviderInfo} sent by the requesting app.
1893 * Always non-null for a {@link #REQUEST_TYPE_APPWIDGET} request, and always null for a
1894 * different request type.
1895 *
Sunny Goyale7712ad2018-03-08 11:23:06 -08001896 * <p>Launcher should not show any configuration activity associated with the provider, and
1897 * assume that the widget is already fully configured. Upon accepting the widget, it should
1898 * pass the widgetId in {@link #accept(Bundle)}.
1899 *
Makoto Onukia37ac3d2017-04-14 12:33:10 -07001900 * @return requested {@link AppWidgetProviderInfo} when a request is of the
1901 * {@link #REQUEST_TYPE_APPWIDGET} type. Null otherwise.
Sunny Goyal87a563e2017-01-01 19:42:45 -08001902 */
1903 @Nullable
Sunny Goyal970d4b42017-01-19 15:07:36 -08001904 public AppWidgetProviderInfo getAppWidgetProviderInfo(Context context) {
Makoto Onuki8abba3a2017-02-24 11:34:54 -08001905 try {
1906 final AppWidgetProviderInfo info = mInner.getAppWidgetProviderInfo();
1907 if (info == null) {
1908 return null;
1909 }
Sunny Goyal970d4b42017-01-19 15:07:36 -08001910 info.updateDimensions(context.getResources().getDisplayMetrics());
1911 return info;
Makoto Onuki8abba3a2017-02-24 11:34:54 -08001912 } catch (RemoteException e) {
1913 throw e.rethrowAsRuntimeException();
Sunny Goyal970d4b42017-01-19 15:07:36 -08001914 }
Sunny Goyal87a563e2017-01-01 19:42:45 -08001915 }
1916
1917 /**
Sunny Goyal4ad6b572017-02-28 11:11:51 -08001918 * Any extras sent by the requesting app.
Makoto Onukia37ac3d2017-04-14 12:33:10 -07001919 *
1920 * @return For a shortcut request, this method always return null. For an AppWidget
1921 * request, this method returns the extras passed to the
1922 * {@link android.appwidget.AppWidgetManager#requestPinAppWidget(
1923 * ComponentName, Bundle, PendingIntent)} API. See {@link AppWidgetManager} for details.
Sunny Goyal4ad6b572017-02-28 11:11:51 -08001924 */
1925 @Nullable
1926 public Bundle getExtras() {
1927 try {
1928 return mInner.getExtras();
1929 } catch (RemoteException e) {
1930 throw e.rethrowAsRuntimeException();
1931 }
1932 }
1933
1934 /**
Makoto Onukia37ac3d2017-04-14 12:33:10 -07001935 * Return whether a request is still valid.
1936 *
1937 * @return {@code TRUE} if a request is valid and {@link #accept(Bundle)} may be called.
Makoto Onuki2d895c32016-12-02 15:48:40 -08001938 */
1939 public boolean isValid() {
1940 try {
1941 return mInner.isValid();
1942 } catch (RemoteException e) {
1943 return false;
1944 }
1945 }
1946
1947 /**
1948 * Called by the receiving launcher app when the user accepts the request.
Makoto Onukia37ac3d2017-04-14 12:33:10 -07001949 *
1950 * @param options must be set for a {@link #REQUEST_TYPE_APPWIDGET} request.
1951 *
1952 * @return {@code TRUE} if the shortcut or the AppWidget has actually been pinned.
1953 * {@code FALSE} if the item hasn't been pinned, for example, because the request had
1954 * already been canceled, in which case the launcher must not pin the requested item.
Makoto Onuki2d895c32016-12-02 15:48:40 -08001955 */
1956 public boolean accept(@Nullable Bundle options) {
1957 try {
1958 return mInner.accept(options);
1959 } catch (RemoteException e) {
1960 throw e.rethrowFromSystemServer();
1961 }
1962 }
1963
1964 /**
Makoto Onukia37ac3d2017-04-14 12:33:10 -07001965 * Called by the receiving launcher app when the user accepts the request, with no options.
1966 *
1967 * @return {@code TRUE} if the shortcut or the AppWidget has actually been pinned.
1968 * {@code FALSE} if the item hasn't been pinned, for example, because the request had
1969 * already been canceled, in which case the launcher must not pin the requested item.
Makoto Onuki2d895c32016-12-02 15:48:40 -08001970 */
1971 public boolean accept() {
1972 return accept(/* options= */ null);
1973 }
1974
1975 private PinItemRequest(Parcel source) {
1976 final ClassLoader cl = getClass().getClassLoader();
1977
1978 mRequestType = source.readInt();
Makoto Onuki2d895c32016-12-02 15:48:40 -08001979 mInner = IPinItemRequest.Stub.asInterface(source.readStrongBinder());
1980 }
1981
1982 @Override
1983 public void writeToParcel(Parcel dest, int flags) {
1984 dest.writeInt(mRequestType);
Makoto Onuki2d895c32016-12-02 15:48:40 -08001985 dest.writeStrongBinder(mInner.asBinder());
1986 }
1987
Jeff Sharkey9e8f83d2019-02-28 12:06:45 -07001988 public static final @android.annotation.NonNull Creator<PinItemRequest> CREATOR =
Makoto Onuki2d895c32016-12-02 15:48:40 -08001989 new Creator<PinItemRequest>() {
1990 public PinItemRequest createFromParcel(Parcel source) {
1991 return new PinItemRequest(source);
1992 }
1993 public PinItemRequest[] newArray(int size) {
1994 return new PinItemRequest[size];
1995 }
1996 };
1997
1998 @Override
1999 public int describeContents() {
2000 return 0;
2001 }
2002 }
Varun Shah2546cef2019-01-11 15:50:54 -08002003
2004 /**
2005 * A class that encapsulates information about the usage limit set for an app or
2006 * a group of apps.
2007 *
Varun Shah9c6f72b2019-01-25 21:13:56 -08002008 * <p>The launcher can query specifics about the usage limit such as how much usage time
2009 * the limit has and how much of the total usage time is remaining via the APIs available
2010 * in this class.
Varun Shah2546cef2019-01-11 15:50:54 -08002011 *
2012 * @see #getAppUsageLimit(String, UserHandle)
Sunny Goyalbeee1972019-03-29 11:38:16 -07002013 * @hide
Varun Shah2546cef2019-01-11 15:50:54 -08002014 */
Sunny Goyalbeee1972019-03-29 11:38:16 -07002015 @SystemApi
Varun Shah2546cef2019-01-11 15:50:54 -08002016 public static final class AppUsageLimit implements Parcelable {
Varun Shah2546cef2019-01-11 15:50:54 -08002017 private final long mTotalUsageLimit;
2018 private final long mUsageRemaining;
2019
2020 /** @hide */
Varun Shah9c6f72b2019-01-25 21:13:56 -08002021 public AppUsageLimit(long totalUsageLimit, long usageRemaining) {
Varun Shah2546cef2019-01-11 15:50:54 -08002022 this.mTotalUsageLimit = totalUsageLimit;
2023 this.mUsageRemaining = usageRemaining;
2024 }
2025
2026 /**
Varun Shah2546cef2019-01-11 15:50:54 -08002027 * Returns the total usage limit in milliseconds set for an app or a group of apps.
2028 *
2029 * @return the total usage limit in milliseconds
2030 */
2031 public long getTotalUsageLimit() {
2032 return mTotalUsageLimit;
2033 }
2034
2035 /**
2036 * Returns the usage remaining in milliseconds for an app or the group of apps
2037 * this limit refers to.
2038 *
2039 * @return the usage remaining in milliseconds
2040 */
2041 public long getUsageRemaining() {
2042 return mUsageRemaining;
2043 }
2044
2045 private AppUsageLimit(Parcel source) {
Varun Shah2546cef2019-01-11 15:50:54 -08002046 mTotalUsageLimit = source.readLong();
2047 mUsageRemaining = source.readLong();
2048 }
2049
Jeff Sharkey9e8f83d2019-02-28 12:06:45 -07002050 public static final @android.annotation.NonNull Creator<AppUsageLimit> CREATOR = new Creator<AppUsageLimit>() {
Varun Shah2546cef2019-01-11 15:50:54 -08002051 @Override
2052 public AppUsageLimit createFromParcel(Parcel source) {
2053 return new AppUsageLimit(source);
2054 }
2055
2056 @Override
2057 public AppUsageLimit[] newArray(int size) {
2058 return new AppUsageLimit[size];
2059 }
2060 };
2061
2062 @Override
2063 public int describeContents() {
2064 return 0;
2065 }
2066
2067 @Override
2068 public void writeToParcel(Parcel dest, int flags) {
Varun Shah2546cef2019-01-11 15:50:54 -08002069 dest.writeLong(mTotalUsageLimit);
2070 dest.writeLong(mUsageRemaining);
2071 }
2072 }
Amith Yamasani4f582632014-02-19 14:31:52 -08002073}