blob: 7fda9aadff6ab68318ac31f404e707170c3cb81e [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
Jon Miranda2b340a22019-01-25 14:03:49 -080019import android.annotation.CallbackExecutor;
Makoto Onuki6f7362d92016-03-04 13:39:41 -080020import android.annotation.IntDef;
21import android.annotation.NonNull;
22import android.annotation.Nullable;
Makoto Onuki2d895c32016-12-02 15:48:40 -080023import android.annotation.SdkConstant;
24import android.annotation.SdkConstant.SdkConstantType;
Sunny Goyalbeee1972019-03-29 11:38:16 -070025import android.annotation.SystemApi;
Makoto Onukib1588c02017-10-12 15:11:45 -070026import android.annotation.SystemService;
Makoto Onuki5ba0d3e2016-04-11 14:03:46 -070027import android.annotation.TestApi;
Makoto Onukia37ac3d2017-04-14 12:33:10 -070028import android.app.PendingIntent;
29import android.appwidget.AppWidgetManager;
Sunny Goyal87a563e2017-01-01 19:42:45 -080030import android.appwidget.AppWidgetProviderInfo;
Artur Satayeve23a0eb2019-12-10 17:47:52 +000031import android.compat.annotation.UnsupportedAppUsage;
Makoto Onuki83f6d2d2016-07-11 14:30:19 -070032import android.content.ActivityNotFoundException;
Amith Yamasani4f582632014-02-19 14:31:52 -080033import android.content.ComponentName;
34import android.content.Context;
35import android.content.Intent;
Sunny Goyala6be88a2017-01-12 16:27:58 -080036import android.content.IntentSender;
Mehdi Alizadehae808ff2020-01-21 13:39:53 -080037import android.content.LocusId;
Jon Miranda2b340a22019-01-25 14:03:49 -080038import android.content.pm.PackageInstaller.SessionCallback;
39import android.content.pm.PackageInstaller.SessionCallbackDelegate;
40import android.content.pm.PackageInstaller.SessionInfo;
Kenny Guy77242752016-01-15 13:29:06 +000041import android.content.pm.PackageManager.ApplicationInfoFlags;
Makoto Onuki04b9aab2016-05-23 17:13:30 -070042import android.content.pm.PackageManager.NameNotFoundException;
43import android.content.res.Resources;
44import android.graphics.Bitmap;
45import android.graphics.BitmapFactory;
Amith Yamasani4f582632014-02-19 14:31:52 -080046import android.graphics.Rect;
Makoto Onukib1588c02017-10-12 15:11:45 -070047import android.graphics.drawable.AdaptiveIconDrawable;
Makoto Onuki04b9aab2016-05-23 17:13:30 -070048import android.graphics.drawable.BitmapDrawable;
Makoto Onuki20c95f82016-05-11 16:51:01 -070049import android.graphics.drawable.Drawable;
Makoto Onuki2d895c32016-12-02 15:48:40 -080050import android.graphics.drawable.Icon;
Mathew Inwood8c854f82018-09-14 12:35:36 +010051import android.os.Build;
Amith Yamasani4f582632014-02-19 14:31:52 -080052import android.os.Bundle;
Kenny Guyb42c89b2014-07-28 19:20:07 +010053import android.os.Handler;
54import android.os.Looper;
55import android.os.Message;
Makoto Onuki2d895c32016-12-02 15:48:40 -080056import android.os.Parcel;
Makoto Onuki6f7362d92016-03-04 13:39:41 -080057import android.os.ParcelFileDescriptor;
Makoto Onuki2d895c32016-12-02 15:48:40 -080058import android.os.Parcelable;
Amith Yamasani4f582632014-02-19 14:31:52 -080059import android.os.RemoteException;
Makoto Onuki5ba0d3e2016-04-11 14:03:46 -070060import android.os.ServiceManager;
Amith Yamasani4f582632014-02-19 14:31:52 -080061import android.os.UserHandle;
Amith Yamasanie781c812014-05-28 15:28:18 -070062import android.os.UserManager;
Makoto Onuki04b9aab2016-05-23 17:13:30 -070063import android.util.DisplayMetrics;
Amith Yamasani4f582632014-02-19 14:31:52 -080064import android.util.Log;
Mehdi Alizadeh9f680192020-01-16 18:09:24 -080065import android.util.Pair;
66
67import com.android.internal.util.function.pooled.PooledLambda;
Amith Yamasani4f582632014-02-19 14:31:52 -080068
Makoto Onuki04b9aab2016-05-23 17:13:30 -070069import java.io.IOException;
Makoto Onuki6f7362d92016-03-04 13:39:41 -080070import java.lang.annotation.Retention;
71import java.lang.annotation.RetentionPolicy;
Mehdi Alizadeh9f680192020-01-16 18:09:24 -080072import java.lang.ref.WeakReference;
Amith Yamasani4f582632014-02-19 14:31:52 -080073import java.util.ArrayList;
Makoto Onukib6d35232016-04-04 15:57:17 -070074import java.util.Arrays;
Amith Yamasani4f582632014-02-19 14:31:52 -080075import java.util.Collections;
Mehdi Alizadeh9f680192020-01-16 18:09:24 -080076import java.util.HashMap;
Jon Miranda2b340a22019-01-25 14:03:49 -080077import java.util.Iterator;
Amith Yamasani4f582632014-02-19 14:31:52 -080078import java.util.List;
Mehdi Alizadeh9f680192020-01-16 18:09:24 -080079import java.util.Map;
Daulet Zhanguzina2044e12019-12-30 16:34:59 +000080import java.util.Objects;
Jon Miranda2b340a22019-01-25 14:03:49 -080081import java.util.concurrent.Executor;
Amith Yamasani4f582632014-02-19 14:31:52 -080082
83/**
84 * Class for retrieving a list of launchable activities for the current user and any associated
Makoto Onukiaecbd032017-01-19 12:11:11 -080085 * managed profiles that are visible to the current user, which can be retrieved with
86 * {@link #getProfiles}. This is mainly for use by launchers.
87 *
88 * Apps can be queried for each user profile.
Amith Yamasani4f582632014-02-19 14:31:52 -080089 * Since the PackageManager will not deliver package broadcasts for other profiles, you can register
90 * for package changes here.
Amith Yamasanie781c812014-05-28 15:28:18 -070091 * <p>
92 * To watch for managed profiles being added or removed, register for the following broadcasts:
93 * {@link Intent#ACTION_MANAGED_PROFILE_ADDED} and {@link Intent#ACTION_MANAGED_PROFILE_REMOVED}.
94 * <p>
Makoto Onukiaecbd032017-01-19 12:11:11 -080095 * Note as of Android O, apps on a managed profile are no longer allowed to access apps on the
96 * main profile. Apps can only access profiles returned by {@link #getProfiles()}.
Amith Yamasani4f582632014-02-19 14:31:52 -080097 */
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -060098@SystemService(Context.LAUNCHER_APPS_SERVICE)
Amith Yamasani4f582632014-02-19 14:31:52 -080099public class LauncherApps {
100
101 static final String TAG = "LauncherApps";
102 static final boolean DEBUG = false;
103
Makoto Onuki2d895c32016-12-02 15:48:40 -0800104 /**
105 * Activity Action: For the default launcher to show the confirmation dialog to create
106 * a pinned shortcut.
107 *
108 * <p>See the {@link ShortcutManager} javadoc for details.
109 *
110 * <p>
111 * Use {@link #getPinItemRequest(Intent)} to get a {@link PinItemRequest} object,
112 * and call {@link PinItemRequest#accept(Bundle)}
113 * if the user accepts. If the user doesn't accept, no further action is required.
114 *
115 * @see #EXTRA_PIN_ITEM_REQUEST
116 */
117 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
Sunny Goyal7f7372a2017-01-24 11:53:54 -0800118 public static final String ACTION_CONFIRM_PIN_SHORTCUT =
119 "android.content.pm.action.CONFIRM_PIN_SHORTCUT";
Makoto Onuki2d895c32016-12-02 15:48:40 -0800120
121 /**
Sunny Goyal7f7372a2017-01-24 11:53:54 -0800122 * Activity Action: For the default launcher to show the confirmation dialog to create
123 * a pinned app widget.
124 *
125 * <p>See the {@link android.appwidget.AppWidgetManager#requestPinAppWidget} javadoc for
126 * details.
127 *
128 * <p>
129 * Use {@link #getPinItemRequest(Intent)} to get a {@link PinItemRequest} object,
130 * and call {@link PinItemRequest#accept(Bundle)}
131 * if the user accepts. If the user doesn't accept, no further action is required.
132 *
133 * @see #EXTRA_PIN_ITEM_REQUEST
134 */
135 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
136 public static final String ACTION_CONFIRM_PIN_APPWIDGET =
137 "android.content.pm.action.CONFIRM_PIN_APPWIDGET";
138
139 /**
140 * An extra for {@link #ACTION_CONFIRM_PIN_SHORTCUT} &amp; {@link #ACTION_CONFIRM_PIN_APPWIDGET}
141 * containing a {@link PinItemRequest} of appropriate type asked to pin.
Makoto Onuki2d895c32016-12-02 15:48:40 -0800142 *
143 * <p>A helper function {@link #getPinItemRequest(Intent)} can be used
144 * instead of using this constant directly.
145 *
Sunny Goyal7f7372a2017-01-24 11:53:54 -0800146 * @see #ACTION_CONFIRM_PIN_SHORTCUT
147 * @see #ACTION_CONFIRM_PIN_APPWIDGET
Makoto Onuki2d895c32016-12-02 15:48:40 -0800148 */
149 public static final String EXTRA_PIN_ITEM_REQUEST =
150 "android.content.pm.extra.PIN_ITEM_REQUEST";
151
Makoto Onukide3c16c2017-01-26 11:39:31 -0800152 private final Context mContext;
Mathew Inwood8c854f82018-09-14 12:35:36 +0100153 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
Makoto Onukide3c16c2017-01-26 11:39:31 -0800154 private final ILauncherApps mService;
Mathew Inwood5c0d3542018-08-14 13:54:31 +0100155 @UnsupportedAppUsage
Makoto Onukide3c16c2017-01-26 11:39:31 -0800156 private final PackageManager mPm;
157 private final UserManager mUserManager;
Amith Yamasani4f582632014-02-19 14:31:52 -0800158
Jon Miranda2b340a22019-01-25 14:03:49 -0800159 private final List<CallbackMessageHandler> mCallbacks = new ArrayList<>();
160 private final List<SessionCallbackDelegate> mDelegates = new ArrayList<>();
Kenny Guyc01545372014-06-16 14:17:26 +0100161
Mehdi Alizadeh9f680192020-01-16 18:09:24 -0800162 private final Map<Integer, Pair<Executor, ShortcutChangeCallback>>
163 mShortcutChangeCallbacks = new HashMap<>();
164
Kenny Guyc01545372014-06-16 14:17:26 +0100165 /**
166 * Callbacks for package changes to this and related managed profiles.
167 */
Kenny Guyf939dba2014-08-15 15:32:34 +0100168 public static abstract class Callback {
Kenny Guyc01545372014-06-16 14:17:26 +0100169 /**
170 * Indicates that a package was removed from the specified profile.
171 *
Kenny Guyb42c89b2014-07-28 19:20:07 +0100172 * If a package is removed while being updated onPackageChanged will be
173 * called instead.
174 *
Kenny Guyc01545372014-06-16 14:17:26 +0100175 * @param packageName The name of the package that was removed.
176 * @param user The UserHandle of the profile that generated the change.
177 */
178 abstract public void onPackageRemoved(String packageName, UserHandle user);
179
180 /**
181 * Indicates that a package was added to the specified profile.
182 *
Kenny Guyb42c89b2014-07-28 19:20:07 +0100183 * If a package is added while being updated then onPackageChanged will be
184 * called instead.
185 *
Kenny Guyc01545372014-06-16 14:17:26 +0100186 * @param packageName The name of the package that was added.
187 * @param user The UserHandle of the profile that generated the change.
188 */
189 abstract public void onPackageAdded(String packageName, UserHandle user);
190
191 /**
192 * Indicates that a package was modified in the specified profile.
Kenny Guyb42c89b2014-07-28 19:20:07 +0100193 * This can happen, for example, when the package is updated or when
194 * one or more components are enabled or disabled.
Kenny Guyc01545372014-06-16 14:17:26 +0100195 *
196 * @param packageName The name of the package that has changed.
197 * @param user The UserHandle of the profile that generated the change.
198 */
199 abstract public void onPackageChanged(String packageName, UserHandle user);
200
201 /**
202 * Indicates that one or more packages have become available. For
203 * example, this can happen when a removable storage card has
204 * reappeared.
205 *
206 * @param packageNames The names of the packages that have become
207 * available.
208 * @param user The UserHandle of the profile that generated the change.
209 * @param replacing Indicates whether these packages are replacing
210 * existing ones.
211 */
212 abstract public void onPackagesAvailable(String[] packageNames, UserHandle user,
213 boolean replacing);
214
215 /**
216 * Indicates that one or more packages have become unavailable. For
217 * example, this can happen when a removable storage card has been
218 * removed.
219 *
220 * @param packageNames The names of the packages that have become
221 * unavailable.
222 * @param user The UserHandle of the profile that generated the change.
223 * @param replacing Indicates whether the packages are about to be
224 * replaced with new versions.
225 */
226 abstract public void onPackagesUnavailable(String[] packageNames, UserHandle user,
227 boolean replacing);
Kenny Guy77242752016-01-15 13:29:06 +0000228
229 /**
230 * Indicates that one or more packages have been suspended. For
231 * example, this can happen when a Device Administrator suspends
232 * an applicaton.
233 *
Suprabh Shukla19b41f32018-03-26 22:35:13 -0700234 * <p>Note: On devices running {@link android.os.Build.VERSION_CODES#P Android P} or higher,
Suprabh Shukla96212bc2018-04-10 15:04:51 -0700235 * any apps that override {@link #onPackagesSuspended(String[], UserHandle, Bundle)} will
Suprabh Shukla19b41f32018-03-26 22:35:13 -0700236 * not receive this callback.
237 *
Kenny Guy77242752016-01-15 13:29:06 +0000238 * @param packageNames The names of the packages that have just been
239 * suspended.
240 * @param user The UserHandle of the profile that generated the change.
241 */
242 public void onPackagesSuspended(String[] packageNames, UserHandle user) {
243 }
244
245 /**
Suprabh Shukla19b41f32018-03-26 22:35:13 -0700246 * Indicates that one or more packages have been suspended. A device administrator or an app
247 * with {@code android.permission.SUSPEND_APPS} can do this.
248 *
Suprabh Shukla96212bc2018-04-10 15:04:51 -0700249 * <p>A suspending app with the permission {@code android.permission.SUSPEND_APPS} can
250 * optionally provide a {@link Bundle} of extra information that it deems helpful for the
251 * launcher to handle the suspended state of these packages. The contents of this
Suprabh Shukla3e03ab92018-04-11 16:03:49 -0700252 * {@link Bundle} are supposed to be a contract between the suspending app and the launcher.
Suprabh Shukla19b41f32018-03-26 22:35:13 -0700253 *
Suprabh Shukla96212bc2018-04-10 15:04:51 -0700254 * @param packageNames The names of the packages that have just been suspended.
255 * @param user the user for which the given packages were suspended.
256 * @param launcherExtras A {@link Bundle} of extras for the launcher, if provided to the
257 * system, {@code null} otherwise.
Suprabh Shukla19b41f32018-03-26 22:35:13 -0700258 * @see PackageManager#isPackageSuspended()
259 * @see #getSuspendedPackageLauncherExtras(String, UserHandle)
Suprabh Shuklad3278442019-08-27 15:58:03 -0700260 * @deprecated {@code launcherExtras} should be obtained by using
261 * {@link #getSuspendedPackageLauncherExtras(String, UserHandle)}. For all other cases,
262 * {@link #onPackagesSuspended(String[], UserHandle)} should be used.
Suprabh Shukla19b41f32018-03-26 22:35:13 -0700263 */
Suprabh Shuklad3278442019-08-27 15:58:03 -0700264 @Deprecated
Suprabh Shukla96212bc2018-04-10 15:04:51 -0700265 public void onPackagesSuspended(String[] packageNames, UserHandle user,
266 @Nullable Bundle launcherExtras) {
Suprabh Shukla19b41f32018-03-26 22:35:13 -0700267 onPackagesSuspended(packageNames, user);
268 }
269
270 /**
Kenny Guy77242752016-01-15 13:29:06 +0000271 * Indicates that one or more packages have been unsuspended. For
272 * example, this can happen when a Device Administrator unsuspends
273 * an applicaton.
274 *
275 * @param packageNames The names of the packages that have just been
276 * unsuspended.
277 * @param user The UserHandle of the profile that generated the change.
278 */
279 public void onPackagesUnsuspended(String[] packageNames, UserHandle user) {
280 }
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800281
282 /**
Makoto Onukife9c9662016-07-25 15:12:23 -0700283 * Indicates that one or more shortcuts of any kind (dynamic, pinned, or manifest)
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800284 * have been added, updated or removed.
285 *
Makoto Onuki2d5b4652016-03-11 16:09:54 -0800286 * <p>Only the applications that are allowed to access the shortcut information,
287 * as defined in {@link #hasShortcutHostPermission()}, will receive it.
288 *
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800289 * @param packageName The name of the package that has the shortcuts.
Makoto Onukife9c9662016-07-25 15:12:23 -0700290 * @param shortcuts All shortcuts from the package (dynamic, manifest and/or pinned).
291 * Only "key" information will be provided, as defined in
Makoto Onuki4d6b87f2016-06-17 13:47:40 -0700292 * {@link ShortcutInfo#hasKeyFieldsOnly()}.
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800293 * @param user The UserHandle of the profile that generated the change.
Makoto Onuki4a910962016-07-07 13:57:34 -0700294 *
295 * @see ShortcutManager
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800296 */
297 public void onShortcutsChanged(@NonNull String packageName,
298 @NonNull List<ShortcutInfo> shortcuts, @NonNull UserHandle user) {
299 }
300 }
301
302 /**
303 * Represents a query passed to {@link #getShortcuts(ShortcutQuery, UserHandle)}.
304 */
305 public static class ShortcutQuery {
306 /**
307 * Include dynamic shortcuts in the result.
308 */
Makoto Onukib5a012f2016-06-21 11:13:53 -0700309 public static final int FLAG_MATCH_DYNAMIC = 1 << 0;
310
311 /** @hide kept for unit tests */
312 @Deprecated
313 public static final int FLAG_GET_DYNAMIC = FLAG_MATCH_DYNAMIC;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800314
315 /**
316 * Include pinned shortcuts in the result.
Makoto Onuki88b4dcc2017-12-07 15:53:56 -0800317 *
318 * <p>If you are the selected assistant app, and wishes to fetch all shortcuts that the
319 * user owns on the launcher (or by other launchers, in case the user has multiple), use
320 * {@link #FLAG_MATCH_PINNED_BY_ANY_LAUNCHER} instead.
321 *
322 * <p>If you're a regular launcher app, there's no way to get shortcuts pinned by other
323 * launchers, and {@link #FLAG_MATCH_PINNED_BY_ANY_LAUNCHER} will be ignored. So use this
324 * flag to get own pinned shortcuts.
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800325 */
Makoto Onukib5a012f2016-06-21 11:13:53 -0700326 public static final int FLAG_MATCH_PINNED = 1 << 1;
327
328 /** @hide kept for unit tests */
329 @Deprecated
330 public static final int FLAG_GET_PINNED = FLAG_MATCH_PINNED;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800331
332 /**
Makoto Onuki22fcc682016-05-17 14:52:19 -0700333 * Include manifest shortcuts in the result.
334 */
Makoto Onukib5a012f2016-06-21 11:13:53 -0700335 public static final int FLAG_MATCH_MANIFEST = 1 << 3;
336
Mehdi Alizadeh505fb762020-01-21 17:26:24 -0800337 /**
338 * Include cached shortcuts in the result.
339 */
340 public static final int FLAG_MATCH_CACHED = 1 << 4;
341
Makoto Onukib5a012f2016-06-21 11:13:53 -0700342 /** @hide kept for unit tests */
343 @Deprecated
344 public static final int FLAG_GET_MANIFEST = FLAG_MATCH_MANIFEST;
Makoto Onuki22fcc682016-05-17 14:52:19 -0700345
Hakan Seyalioglu58fc95d2016-12-13 15:23:22 -0800346 /**
Makoto Onuki35559d62017-11-06 16:26:32 -0800347 * Include all pinned shortcuts by any launchers, not just by the caller,
Makoto Onuki634cecb2017-10-13 17:10:48 -0700348 * in the result.
Makoto Onuki35559d62017-11-06 16:26:32 -0800349 *
Makoto Onuki88b4dcc2017-12-07 15:53:56 -0800350 * <p>The caller must be the selected assistant app to use this flag, or have the system
Makoto Onuki35559d62017-11-06 16:26:32 -0800351 * {@code ACCESS_SHORTCUTS} permission.
Makoto Onuki88b4dcc2017-12-07 15:53:56 -0800352 *
353 * <p>If you are the selected assistant app, and wishes to fetch all shortcuts that the
354 * user owns on the launcher (or by other launchers, in case the user has multiple), use
355 * {@link #FLAG_MATCH_PINNED_BY_ANY_LAUNCHER} instead.
356 *
357 * <p>If you're a regular launcher app (or any app that's not the selected assistant app)
358 * then this flag will be ignored.
Makoto Onuki634cecb2017-10-13 17:10:48 -0700359 */
Makoto Onuki35559d62017-11-06 16:26:32 -0800360 public static final int FLAG_MATCH_PINNED_BY_ANY_LAUNCHER = 1 << 10;
Makoto Onuki634cecb2017-10-13 17:10:48 -0700361
362 /**
Mehdi Alizadeh505fb762020-01-21 17:26:24 -0800363 * FLAG_MATCH_DYNAMIC | FLAG_MATCH_PINNED | FLAG_MATCH_MANIFEST | FLAG_MATCH_CACHED
Hakan Seyalioglu58fc95d2016-12-13 15:23:22 -0800364 * @hide
365 */
Makoto Onukib5a012f2016-06-21 11:13:53 -0700366 public static final int FLAG_MATCH_ALL_KINDS =
Mehdi Alizadeh505fb762020-01-21 17:26:24 -0800367 FLAG_MATCH_DYNAMIC | FLAG_MATCH_PINNED | FLAG_MATCH_MANIFEST | FLAG_MATCH_CACHED;
Makoto Onuki634cecb2017-10-13 17:10:48 -0700368
369 /**
370 * FLAG_MATCH_DYNAMIC | FLAG_MATCH_PINNED | FLAG_MATCH_MANIFEST | FLAG_MATCH_ALL_PINNED
371 * @hide
372 */
373 public static final int FLAG_MATCH_ALL_KINDS_WITH_ALL_PINNED =
Makoto Onuki35559d62017-11-06 16:26:32 -0800374 FLAG_MATCH_ALL_KINDS | FLAG_MATCH_PINNED_BY_ANY_LAUNCHER;
Makoto Onuki4d6b87f2016-06-17 13:47:40 -0700375
Makoto Onukib5a012f2016-06-21 11:13:53 -0700376 /** @hide kept for unit tests */
377 @Deprecated
378 public static final int FLAG_GET_ALL_KINDS = FLAG_MATCH_ALL_KINDS;
379
Makoto Onuki22fcc682016-05-17 14:52:19 -0700380 /**
Makoto Onukife9c9662016-07-25 15:12:23 -0700381 * Requests "key" fields only. See {@link ShortcutInfo#hasKeyFieldsOnly()}'s javadoc to
382 * see which fields fields "key".
383 * This allows quicker access to shortcut information in order to
384 * determine whether the caller's in-memory cache needs to be updated.
Makoto Onuki4a910962016-07-07 13:57:34 -0700385 *
Makoto Onukife9c9662016-07-25 15:12:23 -0700386 * <p>Typically, launcher applications cache all or most shortcut information
387 * in memory in order to show shortcuts without a delay.
388 *
389 * When a given launcher application wants to update its cache, such as when its process
390 * restarts, it can fetch shortcut information with this flag.
391 * The application can then check {@link ShortcutInfo#getLastChangedTimestamp()} for each
392 * shortcut, fetching a shortcut's non-key information only if that shortcut has been
393 * updated.
Makoto Onuki4a910962016-07-07 13:57:34 -0700394 *
395 * @see ShortcutManager
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800396 */
397 public static final int FLAG_GET_KEY_FIELDS_ONLY = 1 << 2;
398
399 /** @hide */
Jeff Sharkeyce8db992017-12-13 20:05:05 -0700400 @IntDef(flag = true, prefix = { "FLAG_" }, value = {
401 FLAG_MATCH_DYNAMIC,
402 FLAG_MATCH_PINNED,
403 FLAG_MATCH_MANIFEST,
Mehdi Alizadeh505fb762020-01-21 17:26:24 -0800404 FLAG_MATCH_CACHED,
Jeff Sharkeyce8db992017-12-13 20:05:05 -0700405 FLAG_GET_KEY_FIELDS_ONLY,
Jeff Sharkeyce8db992017-12-13 20:05:05 -0700406 })
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800407 @Retention(RetentionPolicy.SOURCE)
408 public @interface QueryFlags {}
409
410 long mChangedSince;
411
412 @Nullable
413 String mPackage;
414
415 @Nullable
Makoto Onukiabe84422016-04-07 09:41:19 -0700416 List<String> mShortcutIds;
417
418 @Nullable
Mehdi Alizadehae808ff2020-01-21 13:39:53 -0800419 List<LocusId> mLocusIds;
420
421 @Nullable
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800422 ComponentName mActivity;
423
424 @QueryFlags
425 int mQueryFlags;
426
427 public ShortcutQuery() {
428 }
429
430 /**
Makoto Onukife9c9662016-07-25 15:12:23 -0700431 * If non-zero, returns only shortcuts that have been added or updated
432 * since the given timestamp, expressed in milliseconds since the Epoch&mdash;see
433 * {@link System#currentTimeMillis()}.
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800434 */
Makoto Onuki22fcc682016-05-17 14:52:19 -0700435 public ShortcutQuery setChangedSince(long changedSince) {
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800436 mChangedSince = changedSince;
Makoto Onuki22fcc682016-05-17 14:52:19 -0700437 return this;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800438 }
439
440 /**
441 * If non-null, returns only shortcuts from the package.
442 */
Makoto Onuki22fcc682016-05-17 14:52:19 -0700443 public ShortcutQuery setPackage(@Nullable String packageName) {
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800444 mPackage = packageName;
Makoto Onuki22fcc682016-05-17 14:52:19 -0700445 return this;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800446 }
447
448 /**
Makoto Onukiabe84422016-04-07 09:41:19 -0700449 * If non-null, return only the specified shortcuts by ID. When setting this field,
Makoto Onuki4a910962016-07-07 13:57:34 -0700450 * a package name must also be set with {@link #setPackage}.
Makoto Onukiabe84422016-04-07 09:41:19 -0700451 */
Makoto Onuki22fcc682016-05-17 14:52:19 -0700452 public ShortcutQuery setShortcutIds(@Nullable List<String> shortcutIds) {
Makoto Onukiabe84422016-04-07 09:41:19 -0700453 mShortcutIds = shortcutIds;
Makoto Onuki22fcc682016-05-17 14:52:19 -0700454 return this;
Makoto Onukiabe84422016-04-07 09:41:19 -0700455 }
456
457 /**
Mehdi Alizadehae808ff2020-01-21 13:39:53 -0800458 * If non-null, return only the specified shortcuts by locus ID. When setting this field,
459 * a package name must also be set with {@link #setPackage}.
460 *
461 * @hide
462 */
463 @SystemApi
464 @NonNull
465 public ShortcutQuery setLocusIds(@Nullable List<LocusId> locusIds) {
466 mLocusIds = locusIds;
467 return this;
468 }
469
470 /**
Makoto Onuki22fcc682016-05-17 14:52:19 -0700471 * If non-null, returns only shortcuts associated with the activity; i.e.
472 * {@link ShortcutInfo}s whose {@link ShortcutInfo#getActivity()} are equal
473 * to {@code activity}.
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800474 */
Makoto Onuki22fcc682016-05-17 14:52:19 -0700475 public ShortcutQuery setActivity(@Nullable ComponentName activity) {
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800476 mActivity = activity;
Makoto Onuki22fcc682016-05-17 14:52:19 -0700477 return this;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800478 }
479
Hakan Seyalioglu58fc95d2016-12-13 15:23:22 -0800480 /**
Makoto Onukife9c9662016-07-25 15:12:23 -0700481 * Set query options. At least one of the {@code MATCH} flags should be set. Otherwise,
482 * no shortcuts will be returned.
Makoto Onuki4a910962016-07-07 13:57:34 -0700483 *
Makoto Onukife9c9662016-07-25 15:12:23 -0700484 * <ul>
485 * <li>{@link #FLAG_MATCH_DYNAMIC}
486 * <li>{@link #FLAG_MATCH_PINNED}
487 * <li>{@link #FLAG_MATCH_MANIFEST}
Mehdi Alizadeh505fb762020-01-21 17:26:24 -0800488 * <li>{@link #FLAG_MATCH_CACHED}
Makoto Onukife9c9662016-07-25 15:12:23 -0700489 * <li>{@link #FLAG_GET_KEY_FIELDS_ONLY}
490 * </ul>
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800491 */
Makoto Onuki22fcc682016-05-17 14:52:19 -0700492 public ShortcutQuery setQueryFlags(@QueryFlags int queryFlags) {
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800493 mQueryFlags = queryFlags;
Makoto Onuki22fcc682016-05-17 14:52:19 -0700494 return this;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800495 }
Kenny Guyc01545372014-06-16 14:17:26 +0100496 }
Amith Yamasani4f582632014-02-19 14:31:52 -0800497
Mehdi Alizadeh9f680192020-01-16 18:09:24 -0800498 /**
499 * Callbacks for shortcut changes to this and related managed profiles.
500 *
501 * @hide
502 */
503 public interface ShortcutChangeCallback {
504 /**
505 * Indicates that one or more shortcuts, that match the {@link ShortcutQuery} used to
506 * register this callback, have been added or updated.
507 * @see LauncherApps#registerShortcutChangeCallback(ShortcutChangeCallback, ShortcutQuery)
508 *
509 * <p>Only the applications that are allowed to access the shortcut information,
510 * as defined in {@link #hasShortcutHostPermission()}, will receive it.
511 *
512 * @param packageName The name of the package that has the shortcuts.
513 * @param shortcuts Shortcuts from the package that have updated or added. Only "key"
514 * information will be provided, as defined in {@link ShortcutInfo#hasKeyFieldsOnly()}.
515 * @param user The UserHandle of the profile that generated the change.
516 *
517 * @see ShortcutManager
518 */
519 default void onShortcutsAddedOrUpdated(@NonNull String packageName,
520 @NonNull List<ShortcutInfo> shortcuts, @NonNull UserHandle user) {}
521
522 /**
523 * Indicates that one or more shortcuts, that match the {@link ShortcutQuery} used to
524 * register this callback, have been removed.
525 * @see LauncherApps#registerShortcutChangeCallback(ShortcutChangeCallback, ShortcutQuery)
526 *
527 * <p>Only the applications that are allowed to access the shortcut information,
528 * as defined in {@link #hasShortcutHostPermission()}, will receive it.
529 *
530 * @param packageName The name of the package that has the shortcuts.
531 * @param shortcuts Shortcuts from the package that have been removed. Only "key"
532 * information will be provided, as defined in {@link ShortcutInfo#hasKeyFieldsOnly()}.
533 * @param user The UserHandle of the profile that generated the change.
534 *
535 * @see ShortcutManager
536 */
537 default void onShortcutsRemoved(@NonNull String packageName,
538 @NonNull List<ShortcutInfo> shortcuts, @NonNull UserHandle user) {}
539 }
540
541 /**
542 * Callback proxy class for {@link ShortcutChangeCallback}
543 *
544 * @hide
545 */
546 private static class ShortcutChangeCallbackProxy extends
547 android.content.pm.IShortcutChangeCallback.Stub {
548 private final WeakReference<Pair<Executor, ShortcutChangeCallback>> mRemoteReferences;
549
550 ShortcutChangeCallbackProxy(Pair<Executor, ShortcutChangeCallback> remoteReferences) {
551 mRemoteReferences = new WeakReference<>(remoteReferences);
552 }
553
554 @Override
555 public void onShortcutsAddedOrUpdated(@NonNull String packageName,
556 @NonNull List<ShortcutInfo> shortcuts, @NonNull UserHandle user) {
557 Pair<Executor, ShortcutChangeCallback> remoteReferences = mRemoteReferences.get();
558 if (remoteReferences == null) {
559 // Binder is dead.
560 return;
561 }
562
563 final Executor executor = remoteReferences.first;
564 final ShortcutChangeCallback callback = remoteReferences.second;
565 executor.execute(
566 PooledLambda.obtainRunnable(ShortcutChangeCallback::onShortcutsAddedOrUpdated,
567 callback, packageName, shortcuts, user).recycleOnUse());
568 }
569
570 @Override
571 public void onShortcutsRemoved(@NonNull String packageName,
572 @NonNull List<ShortcutInfo> shortcuts, @NonNull UserHandle user) {
573 Pair<Executor, ShortcutChangeCallback> remoteReferences = mRemoteReferences.get();
574 if (remoteReferences == null) {
575 // Binder is dead.
576 return;
577 }
578
579 final Executor executor = remoteReferences.first;
580 final ShortcutChangeCallback callback = remoteReferences.second;
581 executor.execute(
582 PooledLambda.obtainRunnable(ShortcutChangeCallback::onShortcutsRemoved,
583 callback, packageName, shortcuts, user).recycleOnUse());
584 }
585 }
586
Amith Yamasani4f582632014-02-19 14:31:52 -0800587 /** @hide */
588 public LauncherApps(Context context, ILauncherApps service) {
589 mContext = context;
590 mService = service;
Amith Yamasanie781c812014-05-28 15:28:18 -0700591 mPm = context.getPackageManager();
Makoto Onukide3c16c2017-01-26 11:39:31 -0800592 mUserManager = context.getSystemService(UserManager.class);
Amith Yamasani4f582632014-02-19 14:31:52 -0800593 }
594
Makoto Onuki5ba0d3e2016-04-11 14:03:46 -0700595 /** @hide */
596 @TestApi
597 public LauncherApps(Context context) {
598 this(context, ILauncherApps.Stub.asInterface(
599 ServiceManager.getService(Context.LAUNCHER_APPS_SERVICE)));
600 }
601
Amith Yamasani4f582632014-02-19 14:31:52 -0800602 /**
Makoto Onukide3c16c2017-01-26 11:39:31 -0800603 * Show an error log on logcat, when the calling user is a managed profile, and the target
604 * user is different from the calling user, in order to help developers to detect it.
605 */
606 private void logErrorForInvalidProfileAccess(@NonNull UserHandle target) {
607 if (UserHandle.myUserId() != target.getIdentifier() && mUserManager.isManagedProfile()) {
Makoto Onuki3cc7cd12017-04-03 12:48:42 -0700608 Log.w(TAG, "Accessing other profiles/users from managed profile is no longer allowed.");
Makoto Onukide3c16c2017-01-26 11:39:31 -0800609 }
610 }
611
612 /**
Makoto Onukiaecbd032017-01-19 12:11:11 -0800613 * Return a list of profiles that the caller can access via the {@link LauncherApps} APIs.
614 *
615 * <p>If the caller is running on a managed profile, it'll return only the current profile.
616 * Otherwise it'll return the same list as {@link UserManager#getUserProfiles()} would.
617 */
618 public List<UserHandle> getProfiles() {
Makoto Onukide3c16c2017-01-26 11:39:31 -0800619 if (mUserManager.isManagedProfile()) {
Makoto Onukiaecbd032017-01-19 12:11:11 -0800620 // If it's a managed profile, only return the current profile.
621 final List result = new ArrayList(1);
622 result.add(android.os.Process.myUserHandle());
623 return result;
624 } else {
Makoto Onukide3c16c2017-01-26 11:39:31 -0800625 return mUserManager.getUserProfiles();
Makoto Onukiaecbd032017-01-19 12:11:11 -0800626 }
627 }
628
629 /**
Kevin Hufnagle25266af2019-08-14 17:23:58 -0700630 * Retrieves a list of activities that specify {@link Intent#ACTION_MAIN} and
631 * {@link Intent#CATEGORY_LAUNCHER}, across all apps, for a specified user. If an app doesn't
632 * have any activities that specify <code>ACTION_MAIN</code> or <code>CATEGORY_LAUNCHER</code>,
633 * the system adds a synthesized activity to the list. This synthesized activity represents the
634 * app's details page within system settings.
635 *
636 * <p class="note"><b>Note: </b>It's possible for system apps, such as app stores, to prevent
637 * the system from adding synthesized activities to the returned list.</p>
638 *
639 * <p>As of <a href="/reference/android/os/Build.VERSION_CODES.html#Q">Android Q</a>, at least
640 * one of the app's activities or synthesized activities appears in the returned list unless the
641 * app satisfies at least one of the following conditions:</p>
642 * <ul>
643 * <li>The app is a system app.</li>
644 * <li>The app doesn't request any <a href="/guide/topics/permissions/overview">permissions</a>.
645 * </li>
Kevin Hufnagleb8779b82019-09-13 02:18:44 +0000646 * <li>The app doesn't have a <em>launcher activity</em> that is enabled by default. A launcher
647 * activity has an intent containing the <code>ACTION_MAIN</code> action and the
648 * <code>CATEGORY_LAUNCHER</code> category.</li>
Kevin Hufnagle25266af2019-08-14 17:23:58 -0700649 * </ul>
650 *
651 * <p>Additionally, the system hides synthesized activities for some or all apps in the
652 * following enterprise-related cases:</p>
653 * <ul>
654 * <li>If the device is a
655 * <a href="https://developers.google.com/android/work/overview#company-owned-devices-for-knowledge-workers">fully
656 * managed device</a>, no synthesized activities for any app appear in the returned list.</li>
657 * <li>If the current user has a
658 * <a href="https://developers.google.com/android/work/overview#employee-owned-devices-byod">work
659 * profile</a>, no synthesized activities for the user's work apps appear in the returned
660 * list.</li>
661 * </ul>
Amith Yamasani4f582632014-02-19 14:31:52 -0800662 *
663 * @param packageName The specific package to query. If null, it checks all installed packages
664 * in the profile.
665 * @param user The UserHandle of the profile.
666 * @return List of launchable activities. Can be an empty list but will not be null.
667 */
668 public List<LauncherActivityInfo> getActivityList(String packageName, UserHandle user) {
Makoto Onukide3c16c2017-01-26 11:39:31 -0800669 logErrorForInvalidProfileAccess(user);
Amith Yamasani4f582632014-02-19 14:31:52 -0800670 try {
Makoto Onuki3a2541e2017-01-24 09:00:15 -0800671 return convertToActivityList(mService.getLauncherActivities(mContext.getPackageName(),
672 packageName, user), user);
Amith Yamasani4f582632014-02-19 14:31:52 -0800673 } catch (RemoteException re) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700674 throw re.rethrowFromSystemServer();
Amith Yamasani4f582632014-02-19 14:31:52 -0800675 }
Amith Yamasani4f582632014-02-19 14:31:52 -0800676 }
677
Amith Yamasani4f582632014-02-19 14:31:52 -0800678 /**
679 * Returns the activity info for a given intent and user handle, if it resolves. Otherwise it
680 * returns null.
681 *
682 * @param intent The intent to find a match for.
683 * @param user The profile to look in for a match.
684 * @return An activity info object if there is a match.
685 */
686 public LauncherActivityInfo resolveActivity(Intent intent, UserHandle user) {
Makoto Onukide3c16c2017-01-26 11:39:31 -0800687 logErrorForInvalidProfileAccess(user);
Amith Yamasani4f582632014-02-19 14:31:52 -0800688 try {
Makoto Onuki3a2541e2017-01-24 09:00:15 -0800689 ActivityInfo ai = mService.resolveActivity(mContext.getPackageName(),
690 intent.getComponent(), user);
Sunny Goyal45d3e972016-03-31 12:38:17 -0700691 if (ai != null) {
692 LauncherActivityInfo info = new LauncherActivityInfo(mContext, ai, user);
Amith Yamasani4f582632014-02-19 14:31:52 -0800693 return info;
694 }
695 } catch (RemoteException re) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700696 throw re.rethrowFromSystemServer();
Amith Yamasani4f582632014-02-19 14:31:52 -0800697 }
698 return null;
699 }
700
701 /**
Kenny Guyf939dba2014-08-15 15:32:34 +0100702 * Starts a Main activity in the specified profile.
Amith Yamasani4f582632014-02-19 14:31:52 -0800703 *
704 * @param component The ComponentName of the activity to launch
Amith Yamasanie781c812014-05-28 15:28:18 -0700705 * @param user The UserHandle of the profile
706 * @param sourceBounds The Rect containing the source bounds of the clicked icon
707 * @param opts Options to pass to startActivity
708 */
Kenny Guyf939dba2014-08-15 15:32:34 +0100709 public void startMainActivity(ComponentName component, UserHandle user, Rect sourceBounds,
Amith Yamasanie781c812014-05-28 15:28:18 -0700710 Bundle opts) {
Makoto Onukide3c16c2017-01-26 11:39:31 -0800711 logErrorForInvalidProfileAccess(user);
Amith Yamasani5abdbb62014-04-08 17:23:46 -0700712 if (DEBUG) {
Kenny Guyf939dba2014-08-15 15:32:34 +0100713 Log.i(TAG, "StartMainActivity " + component + " " + user.getIdentifier());
Amith Yamasani5abdbb62014-04-08 17:23:46 -0700714 }
Amith Yamasani4f582632014-02-19 14:31:52 -0800715 try {
Makoto Onuki1a342742018-04-26 14:56:59 -0700716 mService.startActivityAsUser(mContext.getIApplicationThread(),
Philip P. Moltmann9c5226f2020-01-10 08:53:43 -0800717 mContext.getPackageName(), mContext.getFeatureId(),
Makoto Onuki3a2541e2017-01-24 09:00:15 -0800718 component, sourceBounds, opts, user);
Amith Yamasani4f582632014-02-19 14:31:52 -0800719 } catch (RemoteException re) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700720 throw re.rethrowFromSystemServer();
Amith Yamasani4f582632014-02-19 14:31:52 -0800721 }
722 }
723
724 /**
Jon Miranda2b340a22019-01-25 14:03:49 -0800725 * Starts an activity to show the details of the specified session.
726 *
727 * @param sessionInfo The SessionInfo of the session
728 * @param sourceBounds The Rect containing the source bounds of the clicked icon
729 * @param opts Options to pass to startActivity
730 */
Jon Miranda93505982019-03-08 09:33:42 -0800731 public void startPackageInstallerSessionDetailsActivity(@NonNull SessionInfo sessionInfo,
732 @Nullable Rect sourceBounds, @Nullable Bundle opts) {
Jon Miranda2b340a22019-01-25 14:03:49 -0800733 try {
734 mService.startSessionDetailsActivityAsUser(mContext.getIApplicationThread(),
Philip P. Moltmann9c5226f2020-01-10 08:53:43 -0800735 mContext.getPackageName(), mContext.getFeatureId(), sessionInfo, sourceBounds,
736 opts, sessionInfo.getUser());
Jon Miranda2b340a22019-01-25 14:03:49 -0800737 } catch (RemoteException re) {
738 throw re.rethrowFromSystemServer();
739 }
740 }
741
742 /**
Kenny Guy466d2032014-07-23 12:23:35 +0100743 * Starts the settings activity to show the application details for a
744 * package in the specified profile.
745 *
746 * @param component The ComponentName of the package to launch settings for.
747 * @param user The UserHandle of the profile
748 * @param sourceBounds The Rect containing the source bounds of the clicked icon
749 * @param opts Options to pass to startActivity
750 */
Kenny Guyf939dba2014-08-15 15:32:34 +0100751 public void startAppDetailsActivity(ComponentName component, UserHandle user,
Kenny Guy466d2032014-07-23 12:23:35 +0100752 Rect sourceBounds, Bundle opts) {
Makoto Onukide3c16c2017-01-26 11:39:31 -0800753 logErrorForInvalidProfileAccess(user);
Kenny Guy466d2032014-07-23 12:23:35 +0100754 try {
Makoto Onuki1a342742018-04-26 14:56:59 -0700755 mService.showAppDetailsAsUser(mContext.getIApplicationThread(),
Philip P. Moltmann9c5226f2020-01-10 08:53:43 -0800756 mContext.getPackageName(), mContext.getFeatureId(),
Makoto Onuki3a2541e2017-01-24 09:00:15 -0800757 component, sourceBounds, opts, user);
Kenny Guy466d2032014-07-23 12:23:35 +0100758 } catch (RemoteException re) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700759 throw re.rethrowFromSystemServer();
Kenny Guy466d2032014-07-23 12:23:35 +0100760 }
761 }
762
763 /**
Sunny Goyala6be88a2017-01-12 16:27:58 -0800764 * Retrieves a list of config activities for creating {@link ShortcutInfo}.
765 *
766 * @param packageName The specific package to query. If null, it checks all installed packages
767 * in the profile.
768 * @param user The UserHandle of the profile.
769 * @return List of config activities. Can be an empty list but will not be null.
770 *
771 * @see Intent#ACTION_CREATE_SHORTCUT
772 * @see #getShortcutConfigActivityIntent(LauncherActivityInfo)
773 */
774 public List<LauncherActivityInfo> getShortcutConfigActivityList(@Nullable String packageName,
775 @NonNull UserHandle user) {
Makoto Onukide3c16c2017-01-26 11:39:31 -0800776 logErrorForInvalidProfileAccess(user);
Sunny Goyala6be88a2017-01-12 16:27:58 -0800777 try {
Makoto Onuki3a2541e2017-01-24 09:00:15 -0800778 return convertToActivityList(mService.getShortcutConfigActivities(
779 mContext.getPackageName(), packageName, user),
Sunny Goyala6be88a2017-01-12 16:27:58 -0800780 user);
781 } catch (RemoteException re) {
782 throw re.rethrowFromSystemServer();
783 }
784 }
785
786 private List<LauncherActivityInfo> convertToActivityList(
787 @Nullable ParceledListSlice<ResolveInfo> activities, UserHandle user) {
788 if (activities == null) {
789 return Collections.EMPTY_LIST;
790 }
791 ArrayList<LauncherActivityInfo> lais = new ArrayList<>();
792 for (ResolveInfo ri : activities.getList()) {
793 LauncherActivityInfo lai = new LauncherActivityInfo(mContext, ri.activityInfo, user);
794 if (DEBUG) {
795 Log.v(TAG, "Returning activity for profile " + user + " : "
796 + lai.getComponentName());
797 }
798 lais.add(lai);
799 }
800 return lais;
801 }
802
803 /**
804 * Returns an intent sender which can be used to start the configure activity for creating
805 * custom shortcuts. Use this method if the provider is in another profile as you are not
806 * allowed to start an activity in another profile.
807 *
808 * <p>The caller should receive {@link PinItemRequest} in onActivityResult on
809 * {@link android.app.Activity#RESULT_OK}.
810 *
811 * <p>Callers must be allowed to access the shortcut information, as defined in {@link
812 * #hasShortcutHostPermission()}.
813 *
814 * @param info a configuration activity returned by {@link #getShortcutConfigActivityList}
815 *
816 * @throws IllegalStateException when the user is locked or not running.
817 * @throws SecurityException if {@link #hasShortcutHostPermission()} is false.
818 *
819 * @see #getPinItemRequest(Intent)
820 * @see Intent#ACTION_CREATE_SHORTCUT
821 * @see android.app.Activity#startIntentSenderForResult
822 */
Makoto Onukide3c16c2017-01-26 11:39:31 -0800823 @Nullable
Sunny Goyala6be88a2017-01-12 16:27:58 -0800824 public IntentSender getShortcutConfigActivityIntent(@NonNull LauncherActivityInfo info) {
825 try {
826 return mService.getShortcutConfigActivityIntent(
827 mContext.getPackageName(), info.getComponentName(), info.getUser());
828 } catch (RemoteException re) {
829 throw re.rethrowFromSystemServer();
830 }
831 }
832
833 /**
Kenny Guy53fa4ec2014-04-29 14:24:18 +0100834 * Checks if the package is installed and enabled for a profile.
835 *
836 * @param packageName The package to check.
837 * @param user The UserHandle of the profile.
838 *
839 * @return true if the package exists and is enabled.
840 */
Kenny Guyf939dba2014-08-15 15:32:34 +0100841 public boolean isPackageEnabled(String packageName, UserHandle user) {
Makoto Onukide3c16c2017-01-26 11:39:31 -0800842 logErrorForInvalidProfileAccess(user);
Kenny Guy53fa4ec2014-04-29 14:24:18 +0100843 try {
Makoto Onuki3a2541e2017-01-24 09:00:15 -0800844 return mService.isPackageEnabled(mContext.getPackageName(), packageName, user);
Kenny Guy53fa4ec2014-04-29 14:24:18 +0100845 } catch (RemoteException re) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700846 throw re.rethrowFromSystemServer();
Kenny Guy53fa4ec2014-04-29 14:24:18 +0100847 }
848 }
849
850 /**
Suprabh Shukla19b41f32018-03-26 22:35:13 -0700851 * Gets the launcher extras supplied to the system when the given package was suspended via
852 * {@code PackageManager#setPackagesSuspended(String[], boolean, PersistableBundle,
853 * PersistableBundle, String)}.
854 *
Suprabh Shukla96212bc2018-04-10 15:04:51 -0700855 * <p>The contents of this {@link Bundle} are supposed to be a contract between the suspending
856 * app and the launcher.
857 *
Suprabh Shukla19b41f32018-03-26 22:35:13 -0700858 * <p>Note: This just returns whatever extras were provided to the system, <em>which might
859 * even be {@code null}.</em>
860 *
861 * @param packageName The package for which to fetch the launcher extras.
862 * @param user The {@link UserHandle} of the profile.
863 * @return A {@link Bundle} of launcher extras. Or {@code null} if the package is not currently
864 * suspended.
865 *
Suprabh Shukla96212bc2018-04-10 15:04:51 -0700866 * @see Callback#onPackagesSuspended(String[], UserHandle, Bundle)
Suprabh Shukla19b41f32018-03-26 22:35:13 -0700867 * @see PackageManager#isPackageSuspended()
868 */
869 public @Nullable Bundle getSuspendedPackageLauncherExtras(String packageName, UserHandle user) {
870 logErrorForInvalidProfileAccess(user);
871 try {
872 return mService.getSuspendedPackageLauncherExtras(packageName, user);
873 } catch (RemoteException re) {
874 throw re.rethrowFromSystemServer();
875 }
876 }
877
878 /**
Suprabh Shukla79000492018-12-24 17:03:02 -0800879 * Returns whether a package should be hidden from suggestions to the user. Currently, this
880 * could be done because the package was marked as distracting to the user via
881 * {@code PackageManager.setDistractingPackageRestrictions(String[], int)}.
882 *
883 * @param packageName The package for which to check.
884 * @param user the {@link UserHandle} of the profile.
885 * @return
886 */
887 public boolean shouldHideFromSuggestions(@NonNull String packageName,
888 @NonNull UserHandle user) {
Daulet Zhanguzina2044e12019-12-30 16:34:59 +0000889 Objects.requireNonNull(packageName, "packageName");
890 Objects.requireNonNull(user, "user");
Suprabh Shukla79000492018-12-24 17:03:02 -0800891 try {
892 return mService.shouldHideFromSuggestions(packageName, user);
893 } catch (RemoteException re) {
894 throw re.rethrowFromSystemServer();
895 }
896 }
897
898 /**
Benjamin Miller7afa84c2017-07-17 13:01:35 +0200899 * Returns {@link ApplicationInfo} about an application installed for a specific user profile.
Kenny Guy77242752016-01-15 13:29:06 +0000900 *
Amith Yamasani0d1fd8d2016-10-12 14:21:51 -0700901 * @param packageName The package name of the application
Kenny Guy77242752016-01-15 13:29:06 +0000902 * @param flags Additional option flags {@link PackageManager#getApplicationInfo}
903 * @param user The UserHandle of the profile.
904 *
Benjamin Miller7afa84c2017-07-17 13:01:35 +0200905 * @return {@link ApplicationInfo} containing information about the package. Returns
906 * {@code null} if the package isn't installed for the given profile, or the profile
907 * isn't enabled.
Kenny Guy77242752016-01-15 13:29:06 +0000908 */
Makoto Onuki7c7fbf62017-04-14 11:03:56 -0700909 public ApplicationInfo getApplicationInfo(@NonNull String packageName,
910 @ApplicationInfoFlags int flags, @NonNull UserHandle user)
911 throws PackageManager.NameNotFoundException {
Daulet Zhanguzina2044e12019-12-30 16:34:59 +0000912 Objects.requireNonNull(packageName, "packageName");
913 Objects.requireNonNull(user, "user");
Makoto Onukide3c16c2017-01-26 11:39:31 -0800914 logErrorForInvalidProfileAccess(user);
Kenny Guy77242752016-01-15 13:29:06 +0000915 try {
Makoto Onuki7c7fbf62017-04-14 11:03:56 -0700916 final ApplicationInfo ai = mService
917 .getApplicationInfo(mContext.getPackageName(), packageName, flags, user);
918 if (ai == null) {
919 throw new NameNotFoundException("Package " + packageName + " not found for user "
920 + user.getIdentifier());
921 }
922 return ai;
Kenny Guy77242752016-01-15 13:29:06 +0000923 } catch (RemoteException re) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700924 throw re.rethrowFromSystemServer();
Kenny Guy77242752016-01-15 13:29:06 +0000925 }
926 }
927
928 /**
Varun Shah2546cef2019-01-11 15:50:54 -0800929 * Returns an object describing the app usage limit for the given package.
930 * If there are multiple limits that apply to the package, the one with the smallest
931 * time remaining will be returned.
932 *
933 * @param packageName name of the package whose app usage limit will be returned
934 * @param user the user of the package
935 *
936 * @return an {@link AppUsageLimit} object describing the app time limit containing
937 * the given package with the smallest time remaining, or {@code null} if none exist.
Varun Shahe9abb752019-02-11 11:25:06 -0800938 * @throws SecurityException when the caller is not the recents app.
Sunny Goyalbeee1972019-03-29 11:38:16 -0700939 * @hide
Varun Shah2546cef2019-01-11 15:50:54 -0800940 */
941 @Nullable
Sunny Goyalbeee1972019-03-29 11:38:16 -0700942 @SystemApi
Varun Shah2c9263c2019-02-15 10:51:10 -0800943 public LauncherApps.AppUsageLimit getAppUsageLimit(@NonNull String packageName,
944 @NonNull UserHandle user) {
Varun Shah2546cef2019-01-11 15:50:54 -0800945 try {
946 return mService.getAppUsageLimit(mContext.getPackageName(), packageName, user);
947 } catch (RemoteException re) {
948 throw re.rethrowFromSystemServer();
949 }
950 }
951
952 /**
Kenny Guy53fa4ec2014-04-29 14:24:18 +0100953 * Checks if the activity exists and it enabled for a profile.
954 *
Makoto Onuki516020a2019-01-28 14:16:42 -0800955 * <p>The activity may still not be exported, in which case {@link #startMainActivity} will
956 * throw a {@link SecurityException} unless the caller has the same UID as the target app's.
957 *
Kenny Guy53fa4ec2014-04-29 14:24:18 +0100958 * @param component The activity to check.
959 * @param user The UserHandle of the profile.
960 *
961 * @return true if the activity exists and is enabled.
962 */
Kenny Guyf939dba2014-08-15 15:32:34 +0100963 public boolean isActivityEnabled(ComponentName component, UserHandle user) {
Makoto Onukide3c16c2017-01-26 11:39:31 -0800964 logErrorForInvalidProfileAccess(user);
Kenny Guy53fa4ec2014-04-29 14:24:18 +0100965 try {
Makoto Onuki3a2541e2017-01-24 09:00:15 -0800966 return mService.isActivityEnabled(mContext.getPackageName(), component, user);
Kenny Guy53fa4ec2014-04-29 14:24:18 +0100967 } catch (RemoteException re) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700968 throw re.rethrowFromSystemServer();
Kenny Guy53fa4ec2014-04-29 14:24:18 +0100969 }
970 }
971
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800972 /**
Dianne Hackbornc160fa42017-11-01 16:14:26 -0700973 * Returns whether the caller can access the shortcut information. Access is currently
974 * available to:
Makoto Onuki2d5b4652016-03-11 16:09:54 -0800975 *
Dianne Hackbornc160fa42017-11-01 16:14:26 -0700976 * <ul>
977 * <li>The current launcher (or default launcher if there is no set current launcher).</li>
978 * <li>The currently active voice interaction service.</li>
979 * </ul>
Makoto Onuki2d5b4652016-03-11 16:09:54 -0800980 *
Makoto Onuki4a910962016-07-07 13:57:34 -0700981 * <p>Note when this method returns {@code false}, it may be a temporary situation because
Makoto Onuki2d5b4652016-03-11 16:09:54 -0800982 * the user is trying a new launcher application. The user may decide to change the default
Makoto Onuki4a910962016-07-07 13:57:34 -0700983 * launcher back to the calling application again, so even if a launcher application loses
Makoto Onuki2d5b4652016-03-11 16:09:54 -0800984 * this permission, it does <b>not</b> have to purge pinned shortcut information.
Makoto Onukife9c9662016-07-25 15:12:23 -0700985 * If the calling launcher application contains pinned shortcuts, they will still work,
986 * even though the caller no longer has the shortcut host permission.
Makoto Onuki4a910962016-07-07 13:57:34 -0700987 *
Makoto Onuki02f338e2016-07-29 09:40:40 -0700988 * @throws IllegalStateException when the user is locked.
Makoto Onuki9c850012016-07-26 15:50:50 -0700989 *
Makoto Onuki4a910962016-07-07 13:57:34 -0700990 * @see ShortcutManager
Makoto Onuki2d5b4652016-03-11 16:09:54 -0800991 */
992 public boolean hasShortcutHostPermission() {
993 try {
994 return mService.hasShortcutHostPermission(mContext.getPackageName());
995 } catch (RemoteException re) {
996 throw re.rethrowFromSystemServer();
997 }
998 }
999
Makoto Onukib1588c02017-10-12 15:11:45 -07001000 private List<ShortcutInfo> maybeUpdateDisabledMessage(List<ShortcutInfo> shortcuts) {
1001 if (shortcuts == null) {
1002 return null;
1003 }
1004 for (int i = shortcuts.size() - 1; i >= 0; i--) {
1005 final ShortcutInfo si = shortcuts.get(i);
1006 final String message = ShortcutInfo.getDisabledReasonForRestoreIssue(mContext,
1007 si.getDisabledReason());
1008 if (message != null) {
1009 si.setDisabledMessage(message);
1010 }
1011 }
1012 return shortcuts;
1013 }
1014
Makoto Onuki2d5b4652016-03-11 16:09:54 -08001015 /**
Makoto Onuki4a910962016-07-07 13:57:34 -07001016 * Returns {@link ShortcutInfo}s that match {@code query}.
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001017 *
Makoto Onuki2d5b4652016-03-11 16:09:54 -08001018 * <p>Callers must be allowed to access the shortcut information, as defined in {@link
1019 * #hasShortcutHostPermission()}.
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001020 *
1021 * @param query result includes shortcuts matching this query.
1022 * @param user The UserHandle of the profile.
1023 *
1024 * @return the IDs of {@link ShortcutInfo}s that match the query.
Makoto Onuki02f338e2016-07-29 09:40:40 -07001025 * @throws IllegalStateException when the user is locked, or when the {@code user} user
1026 * is locked or not running.
Makoto Onuki4a910962016-07-07 13:57:34 -07001027 *
1028 * @see ShortcutManager
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001029 */
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001030 @Nullable
1031 public List<ShortcutInfo> getShortcuts(@NonNull ShortcutQuery query,
1032 @NonNull UserHandle user) {
Makoto Onukide3c16c2017-01-26 11:39:31 -08001033 logErrorForInvalidProfileAccess(user);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001034 try {
Makoto Onukib1588c02017-10-12 15:11:45 -07001035 // Note this is the only case we need to update the disabled message for shortcuts
1036 // that weren't restored.
1037 // The restore problem messages are only shown by the user, and publishers will never
1038 // see them. The only other API that the launcher gets shortcuts is the shortcut
1039 // changed callback, but that only returns shortcuts with the "key" information, so
1040 // that won't return disabled message.
1041 return maybeUpdateDisabledMessage(mService.getShortcuts(mContext.getPackageName(),
Mehdi Alizadehae808ff2020-01-21 13:39:53 -08001042 query.mChangedSince, query.mPackage, query.mShortcutIds, query.mLocusIds,
1043 query.mActivity, query.mQueryFlags, user)
Makoto Onukib1588c02017-10-12 15:11:45 -07001044 .getList());
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001045 } catch (RemoteException e) {
1046 throw e.rethrowFromSystemServer();
1047 }
1048 }
1049
1050 /**
Makoto Onukiabe84422016-04-07 09:41:19 -07001051 * @hide // No longer used. Use getShortcuts() instead. Kept for unit tests.
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001052 */
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001053 @Nullable
Makoto Onukib5a012f2016-06-21 11:13:53 -07001054 @Deprecated
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001055 public List<ShortcutInfo> getShortcutInfo(@NonNull String packageName,
1056 @NonNull List<String> ids, @NonNull UserHandle user) {
Makoto Onukiabe84422016-04-07 09:41:19 -07001057 final ShortcutQuery q = new ShortcutQuery();
1058 q.setPackage(packageName);
1059 q.setShortcutIds(ids);
Makoto Onuki4d6b87f2016-06-17 13:47:40 -07001060 q.setQueryFlags(ShortcutQuery.FLAG_GET_ALL_KINDS);
Makoto Onukiabe84422016-04-07 09:41:19 -07001061 return getShortcuts(q, user);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001062 }
1063
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001064 /**
1065 * Pin shortcuts on a package.
1066 *
1067 * <p>This API is <b>NOT</b> cumulative; this will replace all pinned shortcuts for the package.
1068 * However, different launchers may have different set of pinned shortcuts.
1069 *
Makoto Onukife9c9662016-07-25 15:12:23 -07001070 * <p>The calling launcher application must be allowed to access the shortcut information,
1071 * as defined in {@link #hasShortcutHostPermission()}.
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001072 *
1073 * @param packageName The target package name.
1074 * @param shortcutIds The IDs of the shortcut to be pinned.
1075 * @param user The UserHandle of the profile.
Makoto Onuki02f338e2016-07-29 09:40:40 -07001076 * @throws IllegalStateException when the user is locked, or when the {@code user} user
1077 * is locked or not running.
Makoto Onuki4a910962016-07-07 13:57:34 -07001078 *
1079 * @see ShortcutManager
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001080 */
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001081 public void pinShortcuts(@NonNull String packageName, @NonNull List<String> shortcutIds,
1082 @NonNull UserHandle user) {
Makoto Onukide3c16c2017-01-26 11:39:31 -08001083 logErrorForInvalidProfileAccess(user);
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001084 try {
1085 mService.pinShortcuts(mContext.getPackageName(), packageName, shortcutIds, user);
1086 } catch (RemoteException e) {
1087 throw e.rethrowFromSystemServer();
1088 }
1089 }
1090
1091 /**
Makoto Onukib6d35232016-04-04 15:57:17 -07001092 * @hide kept for testing.
Makoto Onukiabe84422016-04-07 09:41:19 -07001093 */
Makoto Onukib5a012f2016-06-21 11:13:53 -07001094 @Deprecated
Makoto Onukiabe84422016-04-07 09:41:19 -07001095 public int getShortcutIconResId(@NonNull ShortcutInfo shortcut) {
Makoto Onukib6d35232016-04-04 15:57:17 -07001096 return shortcut.getIconResourceId();
Makoto Onukiabe84422016-04-07 09:41:19 -07001097 }
1098
1099 /**
Makoto Onukib6d35232016-04-04 15:57:17 -07001100 * @hide kept for testing.
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001101 */
Makoto Onukib5a012f2016-06-21 11:13:53 -07001102 @Deprecated
Makoto Onukiabe84422016-04-07 09:41:19 -07001103 public int getShortcutIconResId(@NonNull String packageName, @NonNull String shortcutId,
1104 @NonNull UserHandle user) {
Makoto Onukib6d35232016-04-04 15:57:17 -07001105 final ShortcutQuery q = new ShortcutQuery();
1106 q.setPackage(packageName);
1107 q.setShortcutIds(Arrays.asList(shortcutId));
Makoto Onuki4d6b87f2016-06-17 13:47:40 -07001108 q.setQueryFlags(ShortcutQuery.FLAG_GET_ALL_KINDS);
Makoto Onukib6d35232016-04-04 15:57:17 -07001109 final List<ShortcutInfo> shortcuts = getShortcuts(q, user);
Makoto Onukiabe84422016-04-07 09:41:19 -07001110
Makoto Onukib6d35232016-04-04 15:57:17 -07001111 return shortcuts.size() > 0 ? shortcuts.get(0).getIconResourceId() : 0;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001112 }
1113
1114 /**
Makoto Onukib5a012f2016-06-21 11:13:53 -07001115 * @hide internal/unit tests only
Makoto Onukiabe84422016-04-07 09:41:19 -07001116 */
1117 public ParcelFileDescriptor getShortcutIconFd(
1118 @NonNull ShortcutInfo shortcut) {
Makoto Onuki22fcc682016-05-17 14:52:19 -07001119 return getShortcutIconFd(shortcut.getPackage(), shortcut.getId(),
Makoto Onukiabe84422016-04-07 09:41:19 -07001120 shortcut.getUserId());
1121 }
1122
1123 /**
Makoto Onukib5a012f2016-06-21 11:13:53 -07001124 * @hide internal/unit tests only
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001125 */
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001126 public ParcelFileDescriptor getShortcutIconFd(
Makoto Onukiabe84422016-04-07 09:41:19 -07001127 @NonNull String packageName, @NonNull String shortcutId, @NonNull UserHandle user) {
1128 return getShortcutIconFd(packageName, shortcutId, user.getIdentifier());
1129 }
1130
1131 private ParcelFileDescriptor getShortcutIconFd(
1132 @NonNull String packageName, @NonNull String shortcutId, int userId) {
Makoto Onuki55046222016-03-08 10:49:47 -08001133 try {
Makoto Onukiabe84422016-04-07 09:41:19 -07001134 return mService.getShortcutIconFd(mContext.getPackageName(),
1135 packageName, shortcutId, userId);
Makoto Onuki55046222016-03-08 10:49:47 -08001136 } catch (RemoteException e) {
1137 throw e.rethrowFromSystemServer();
1138 }
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001139 }
1140
Makoto Onuki04b9aab2016-05-23 17:13:30 -07001141 /**
1142 * Returns the icon for this shortcut, without any badging for the profile.
1143 *
Makoto Onukife9c9662016-07-25 15:12:23 -07001144 * <p>The calling launcher application must be allowed to access the shortcut information,
1145 * as defined in {@link #hasShortcutHostPermission()}.
Makoto Onuki4a910962016-07-07 13:57:34 -07001146 *
Makoto Onuki04b9aab2016-05-23 17:13:30 -07001147 * @param density The preferred density of the icon, zero for default density. Use
1148 * density DPI values from {@link DisplayMetrics}.
Makoto Onuki4a910962016-07-07 13:57:34 -07001149 *
1150 * @return The drawable associated with the shortcut.
Makoto Onuki02f338e2016-07-29 09:40:40 -07001151 * @throws IllegalStateException when the user is locked, or when the {@code user} user
1152 * is locked or not running.
Makoto Onuki4a910962016-07-07 13:57:34 -07001153 *
1154 * @see ShortcutManager
Makoto Onuki04b9aab2016-05-23 17:13:30 -07001155 * @see #getShortcutBadgedIconDrawable(ShortcutInfo, int)
1156 * @see DisplayMetrics
Makoto Onuki04b9aab2016-05-23 17:13:30 -07001157 */
1158 public Drawable getShortcutIconDrawable(@NonNull ShortcutInfo shortcut, int density) {
1159 if (shortcut.hasIconFile()) {
1160 final ParcelFileDescriptor pfd = getShortcutIconFd(shortcut);
1161 if (pfd == null) {
1162 return null;
1163 }
1164 try {
1165 final Bitmap bmp = BitmapFactory.decodeFileDescriptor(pfd.getFileDescriptor());
Hyunyoung Songf281e7a2017-02-13 10:57:42 -08001166 if (bmp != null) {
1167 BitmapDrawable dr = new BitmapDrawable(mContext.getResources(), bmp);
Hyunyoung Songe4179e22017-03-01 12:51:26 -08001168 if (shortcut.hasAdaptiveBitmap()) {
Hyunyoung Songbe8835e2017-02-17 11:25:08 -08001169 return new AdaptiveIconDrawable(null, dr);
Hyunyoung Songf281e7a2017-02-13 10:57:42 -08001170 } else {
1171 return dr;
1172 }
1173 }
1174 return null;
Makoto Onuki04b9aab2016-05-23 17:13:30 -07001175 } finally {
1176 try {
1177 pfd.close();
1178 } catch (IOException ignore) {
1179 }
1180 }
1181 } else if (shortcut.hasIconResource()) {
Makoto Onuki2d895c32016-12-02 15:48:40 -08001182 return loadDrawableResourceFromPackage(shortcut.getPackage(),
1183 shortcut.getIconResourceId(), shortcut.getUserHandle(), density);
1184 } else if (shortcut.getIcon() != null) {
1185 // This happens if a shortcut is pending-approval.
1186 final Icon icon = shortcut.getIcon();
1187 switch (icon.getType()) {
1188 case Icon.TYPE_RESOURCE: {
1189 return loadDrawableResourceFromPackage(shortcut.getPackage(),
1190 icon.getResId(), shortcut.getUserHandle(), density);
Makoto Onuki04b9aab2016-05-23 17:13:30 -07001191 }
Hyunyoung Songf281e7a2017-02-13 10:57:42 -08001192 case Icon.TYPE_BITMAP:
Hyunyoung Songe4179e22017-03-01 12:51:26 -08001193 case Icon.TYPE_ADAPTIVE_BITMAP: {
Makoto Onuki2d895c32016-12-02 15:48:40 -08001194 return icon.loadDrawable(mContext);
1195 }
1196 default:
1197 return null; // Shouldn't happen though.
Makoto Onuki04b9aab2016-05-23 17:13:30 -07001198 }
1199 } else {
1200 return null; // Has no icon.
1201 }
Makoto Onuki20c95f82016-05-11 16:51:01 -07001202 }
1203
Makoto Onuki2d895c32016-12-02 15:48:40 -08001204 private Drawable loadDrawableResourceFromPackage(String packageName, int resId,
1205 UserHandle user, int density) {
1206 try {
1207 if (resId == 0) {
1208 return null; // Shouldn't happen but just in case.
1209 }
1210 final ApplicationInfo ai = getApplicationInfo(packageName, /* flags =*/ 0, user);
1211 final Resources res = mContext.getPackageManager().getResourcesForApplication(ai);
1212 return res.getDrawableForDensity(resId, density);
1213 } catch (NameNotFoundException | Resources.NotFoundException e) {
1214 return null;
1215 }
1216 }
1217
Makoto Onuki04b9aab2016-05-23 17:13:30 -07001218 /**
1219 * Returns the shortcut icon with badging appropriate for the profile.
1220 *
Makoto Onukife9c9662016-07-25 15:12:23 -07001221 * <p>The calling launcher application must be allowed to access the shortcut information,
1222 * as defined in {@link #hasShortcutHostPermission()}.
Makoto Onuki4a910962016-07-07 13:57:34 -07001223 *
Makoto Onuki04b9aab2016-05-23 17:13:30 -07001224 * @param density Optional density for the icon, or 0 to use the default density. Use
Makoto Onuki04b9aab2016-05-23 17:13:30 -07001225 * @return A badged icon for the shortcut.
Makoto Onuki02f338e2016-07-29 09:40:40 -07001226 * @throws IllegalStateException when the user is locked, or when the {@code user} user
1227 * is locked or not running.
Makoto Onuki4a910962016-07-07 13:57:34 -07001228 *
1229 * @see ShortcutManager
Makoto Onukife9c9662016-07-25 15:12:23 -07001230 * @see #getShortcutIconDrawable(ShortcutInfo, int)
Makoto Onuki4a910962016-07-07 13:57:34 -07001231 * @see DisplayMetrics
Makoto Onuki04b9aab2016-05-23 17:13:30 -07001232 */
1233 public Drawable getShortcutBadgedIconDrawable(ShortcutInfo shortcut, int density) {
1234 final Drawable originalIcon = getShortcutIconDrawable(shortcut, density);
1235
1236 return (originalIcon == null) ? null : mContext.getPackageManager().getUserBadgedIcon(
1237 originalIcon, shortcut.getUserHandle());
Makoto Onuki20c95f82016-05-11 16:51:01 -07001238 }
1239
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001240 /**
Makoto Onuki4a910962016-07-07 13:57:34 -07001241 * Starts a shortcut.
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001242 *
Makoto Onukife9c9662016-07-25 15:12:23 -07001243 * <p>The calling launcher application must be allowed to access the shortcut information,
1244 * as defined in {@link #hasShortcutHostPermission()}.
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001245 *
Makoto Onuki43204b82016-03-08 16:16:44 -08001246 * @param packageName The target shortcut package name.
1247 * @param shortcutId The target shortcut ID.
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001248 * @param sourceBounds The Rect containing the source bounds of the clicked icon.
1249 * @param startActivityOptions Options to pass to startActivity.
1250 * @param user The UserHandle of the profile.
Makoto Onuki02f338e2016-07-29 09:40:40 -07001251 * @throws IllegalStateException when the user is locked, or when the {@code user} user
1252 * is locked or not running.
Makoto Onuki83f6d2d2016-07-11 14:30:19 -07001253 *
1254 * @throws android.content.ActivityNotFoundException failed to start shortcut. (e.g.
1255 * the shortcut no longer exists, is disabled, the intent receiver activity doesn't exist, etc)
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001256 */
Makoto Onukid6880792016-06-29 13:37:43 -07001257 public void startShortcut(@NonNull String packageName, @NonNull String shortcutId,
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001258 @Nullable Rect sourceBounds, @Nullable Bundle startActivityOptions,
1259 @NonNull UserHandle user) {
Makoto Onukide3c16c2017-01-26 11:39:31 -08001260 logErrorForInvalidProfileAccess(user);
1261
Makoto Onukid6880792016-06-29 13:37:43 -07001262 startShortcut(packageName, shortcutId, sourceBounds, startActivityOptions,
Makoto Onukiabe84422016-04-07 09:41:19 -07001263 user.getIdentifier());
1264 }
1265
1266 /**
1267 * Launches a shortcut.
1268 *
Makoto Onukife9c9662016-07-25 15:12:23 -07001269 * <p>The calling launcher application must be allowed to access the shortcut information,
1270 * as defined in {@link #hasShortcutHostPermission()}.
Makoto Onukiabe84422016-04-07 09:41:19 -07001271 *
1272 * @param shortcut The target shortcut.
1273 * @param sourceBounds The Rect containing the source bounds of the clicked icon.
1274 * @param startActivityOptions Options to pass to startActivity.
Makoto Onuki02f338e2016-07-29 09:40:40 -07001275 * @throws IllegalStateException when the user is locked, or when the {@code user} user
1276 * is locked or not running.
Makoto Onuki83f6d2d2016-07-11 14:30:19 -07001277 *
1278 * @throws android.content.ActivityNotFoundException failed to start shortcut. (e.g.
1279 * the shortcut no longer exists, is disabled, the intent receiver activity doesn't exist, etc)
Makoto Onukiabe84422016-04-07 09:41:19 -07001280 */
Makoto Onukid6880792016-06-29 13:37:43 -07001281 public void startShortcut(@NonNull ShortcutInfo shortcut,
Makoto Onukiabe84422016-04-07 09:41:19 -07001282 @Nullable Rect sourceBounds, @Nullable Bundle startActivityOptions) {
Makoto Onukid6880792016-06-29 13:37:43 -07001283 startShortcut(shortcut.getPackage(), shortcut.getId(),
Makoto Onukiabe84422016-04-07 09:41:19 -07001284 sourceBounds, startActivityOptions,
1285 shortcut.getUserId());
1286 }
1287
Mathew Inwood5c0d3542018-08-14 13:54:31 +01001288 @UnsupportedAppUsage
Makoto Onukid6880792016-06-29 13:37:43 -07001289 private void startShortcut(@NonNull String packageName, @NonNull String shortcutId,
Makoto Onukiabe84422016-04-07 09:41:19 -07001290 @Nullable Rect sourceBounds, @Nullable Bundle startActivityOptions,
1291 int userId) {
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001292 try {
Philip P. Moltmann9c5226f2020-01-10 08:53:43 -08001293 final boolean success = mService.startShortcut(mContext.getPackageName(), packageName,
1294 null /* default featureId */, shortcutId, sourceBounds, startActivityOptions,
1295 userId);
Makoto Onuki83f6d2d2016-07-11 14:30:19 -07001296 if (!success) {
1297 throw new ActivityNotFoundException("Shortcut could not be started");
1298 }
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001299 } catch (RemoteException e) {
1300 throw e.rethrowFromSystemServer();
1301 }
1302 }
Kenny Guy53fa4ec2014-04-29 14:24:18 +01001303
1304 /**
Jon Miranda2b340a22019-01-25 14:03:49 -08001305 * Registers a callback for changes to packages in this user and managed profiles.
Kenny Guyc01545372014-06-16 14:17:26 +01001306 *
Kenny Guy10a574f2014-08-26 16:17:58 +01001307 * @param callback The callback to register.
Kenny Guyc01545372014-06-16 14:17:26 +01001308 */
Kenny Guy10a574f2014-08-26 16:17:58 +01001309 public void registerCallback(Callback callback) {
1310 registerCallback(callback, null);
Kenny Guyb42c89b2014-07-28 19:20:07 +01001311 }
1312
1313 /**
Jon Miranda2b340a22019-01-25 14:03:49 -08001314 * Registers a callback for changes to packages in this user and managed profiles.
Kenny Guyb42c89b2014-07-28 19:20:07 +01001315 *
Kenny Guy10a574f2014-08-26 16:17:58 +01001316 * @param callback The callback to register.
Kenny Guyb42c89b2014-07-28 19:20:07 +01001317 * @param handler that should be used to post callbacks on, may be null.
1318 */
Kenny Guy10a574f2014-08-26 16:17:58 +01001319 public void registerCallback(Callback callback, Handler handler) {
Kenny Guyc01545372014-06-16 14:17:26 +01001320 synchronized (this) {
Kenny Guy172a2162015-06-19 17:21:28 +01001321 if (callback != null && findCallbackLocked(callback) < 0) {
Kenny Guyb42c89b2014-07-28 19:20:07 +01001322 boolean addedFirstCallback = mCallbacks.size() == 0;
1323 addCallbackLocked(callback, handler);
1324 if (addedFirstCallback) {
Kenny Guyc01545372014-06-16 14:17:26 +01001325 try {
Makoto Onuki4dbe0de2016-03-14 17:31:49 -07001326 mService.addOnAppsChangedListener(mContext.getPackageName(),
1327 mAppsChangedListener);
Kenny Guyc01545372014-06-16 14:17:26 +01001328 } catch (RemoteException re) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001329 throw re.rethrowFromSystemServer();
Kenny Guyc01545372014-06-16 14:17:26 +01001330 }
1331 }
1332 }
1333 }
1334 }
1335
1336 /**
Kenny Guy10a574f2014-08-26 16:17:58 +01001337 * Unregisters a callback that was previously registered.
Kenny Guyc01545372014-06-16 14:17:26 +01001338 *
Kenny Guy10a574f2014-08-26 16:17:58 +01001339 * @param callback The callback to unregister.
1340 * @see #registerCallback(Callback)
Kenny Guyc01545372014-06-16 14:17:26 +01001341 */
Kenny Guy10a574f2014-08-26 16:17:58 +01001342 public void unregisterCallback(Callback callback) {
Kenny Guyc01545372014-06-16 14:17:26 +01001343 synchronized (this) {
Kenny Guyb42c89b2014-07-28 19:20:07 +01001344 removeCallbackLocked(callback);
Kenny Guy44b6dee2014-07-10 18:10:14 +01001345 if (mCallbacks.size() == 0) {
Amith Yamasanie781c812014-05-28 15:28:18 -07001346 try {
1347 mService.removeOnAppsChangedListener(mAppsChangedListener);
1348 } catch (RemoteException re) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001349 throw re.rethrowFromSystemServer();
Amith Yamasanie781c812014-05-28 15:28:18 -07001350 }
Amith Yamasani4f582632014-02-19 14:31:52 -08001351 }
1352 }
1353 }
1354
Kenny Guy172a2162015-06-19 17:21:28 +01001355 /** @return position in mCallbacks for callback or -1 if not present. */
1356 private int findCallbackLocked(Callback callback) {
Kenny Guyb42c89b2014-07-28 19:20:07 +01001357 if (callback == null) {
1358 throw new IllegalArgumentException("Callback cannot be null");
1359 }
1360 final int size = mCallbacks.size();
1361 for (int i = 0; i < size; ++i) {
1362 if (mCallbacks.get(i).mCallback == callback) {
Kenny Guy172a2162015-06-19 17:21:28 +01001363 return i;
Kenny Guyb42c89b2014-07-28 19:20:07 +01001364 }
1365 }
Kenny Guy172a2162015-06-19 17:21:28 +01001366 return -1;
1367 }
1368
1369 private void removeCallbackLocked(Callback callback) {
1370 int pos = findCallbackLocked(callback);
1371 if (pos >= 0) {
1372 mCallbacks.remove(pos);
1373 }
Kenny Guyb42c89b2014-07-28 19:20:07 +01001374 }
1375
Kenny Guyf939dba2014-08-15 15:32:34 +01001376 private void addCallbackLocked(Callback callback, Handler handler) {
Kenny Guyb42c89b2014-07-28 19:20:07 +01001377 // Remove if already present.
1378 removeCallbackLocked(callback);
1379 if (handler == null) {
1380 handler = new Handler();
1381 }
1382 CallbackMessageHandler toAdd = new CallbackMessageHandler(handler.getLooper(), callback);
1383 mCallbacks.add(toAdd);
1384 }
1385
Amith Yamasani4f582632014-02-19 14:31:52 -08001386 private IOnAppsChangedListener.Stub mAppsChangedListener = new IOnAppsChangedListener.Stub() {
1387
1388 @Override
Kenny Guyb42c89b2014-07-28 19:20:07 +01001389 public void onPackageRemoved(UserHandle user, String packageName)
1390 throws RemoteException {
Amith Yamasani4f582632014-02-19 14:31:52 -08001391 if (DEBUG) {
1392 Log.d(TAG, "onPackageRemoved " + user.getIdentifier() + "," + packageName);
1393 }
1394 synchronized (LauncherApps.this) {
Kenny Guyb42c89b2014-07-28 19:20:07 +01001395 for (CallbackMessageHandler callback : mCallbacks) {
1396 callback.postOnPackageRemoved(packageName, user);
Kenny Guyc01545372014-06-16 14:17:26 +01001397 }
Amith Yamasani4f582632014-02-19 14:31:52 -08001398 }
1399 }
1400
1401 @Override
1402 public void onPackageChanged(UserHandle user, String packageName) throws RemoteException {
1403 if (DEBUG) {
1404 Log.d(TAG, "onPackageChanged " + user.getIdentifier() + "," + packageName);
1405 }
1406 synchronized (LauncherApps.this) {
Kenny Guyb42c89b2014-07-28 19:20:07 +01001407 for (CallbackMessageHandler callback : mCallbacks) {
1408 callback.postOnPackageChanged(packageName, user);
Kenny Guyc01545372014-06-16 14:17:26 +01001409 }
Amith Yamasani4f582632014-02-19 14:31:52 -08001410 }
1411 }
1412
1413 @Override
1414 public void onPackageAdded(UserHandle user, String packageName) throws RemoteException {
1415 if (DEBUG) {
1416 Log.d(TAG, "onPackageAdded " + user.getIdentifier() + "," + packageName);
1417 }
1418 synchronized (LauncherApps.this) {
Kenny Guyb42c89b2014-07-28 19:20:07 +01001419 for (CallbackMessageHandler callback : mCallbacks) {
1420 callback.postOnPackageAdded(packageName, user);
Kenny Guyc01545372014-06-16 14:17:26 +01001421 }
Amith Yamasani4f582632014-02-19 14:31:52 -08001422 }
1423 }
1424
1425 @Override
1426 public void onPackagesAvailable(UserHandle user, String[] packageNames, boolean replacing)
1427 throws RemoteException {
1428 if (DEBUG) {
1429 Log.d(TAG, "onPackagesAvailable " + user.getIdentifier() + "," + packageNames);
1430 }
1431 synchronized (LauncherApps.this) {
Kenny Guyb42c89b2014-07-28 19:20:07 +01001432 for (CallbackMessageHandler callback : mCallbacks) {
1433 callback.postOnPackagesAvailable(packageNames, user, replacing);
Kenny Guyc01545372014-06-16 14:17:26 +01001434 }
Amith Yamasani4f582632014-02-19 14:31:52 -08001435 }
1436 }
1437
1438 @Override
1439 public void onPackagesUnavailable(UserHandle user, String[] packageNames, boolean replacing)
1440 throws RemoteException {
1441 if (DEBUG) {
1442 Log.d(TAG, "onPackagesUnavailable " + user.getIdentifier() + "," + packageNames);
1443 }
1444 synchronized (LauncherApps.this) {
Kenny Guyb42c89b2014-07-28 19:20:07 +01001445 for (CallbackMessageHandler callback : mCallbacks) {
1446 callback.postOnPackagesUnavailable(packageNames, user, replacing);
Kenny Guyc01545372014-06-16 14:17:26 +01001447 }
Kenny Guy77242752016-01-15 13:29:06 +00001448 }
1449 }
1450
1451 @Override
Suprabh Shukla19b41f32018-03-26 22:35:13 -07001452 public void onPackagesSuspended(UserHandle user, String[] packageNames,
1453 Bundle launcherExtras)
Kenny Guy77242752016-01-15 13:29:06 +00001454 throws RemoteException {
1455 if (DEBUG) {
1456 Log.d(TAG, "onPackagesSuspended " + user.getIdentifier() + "," + packageNames);
1457 }
1458 synchronized (LauncherApps.this) {
1459 for (CallbackMessageHandler callback : mCallbacks) {
Suprabh Shukla19b41f32018-03-26 22:35:13 -07001460 callback.postOnPackagesSuspended(packageNames, launcherExtras, user);
Kenny Guy77242752016-01-15 13:29:06 +00001461 }
1462 }
1463 }
1464
1465 @Override
1466 public void onPackagesUnsuspended(UserHandle user, String[] packageNames)
1467 throws RemoteException {
1468 if (DEBUG) {
1469 Log.d(TAG, "onPackagesUnsuspended " + user.getIdentifier() + "," + packageNames);
1470 }
1471 synchronized (LauncherApps.this) {
1472 for (CallbackMessageHandler callback : mCallbacks) {
1473 callback.postOnPackagesUnsuspended(packageNames, user);
1474 }
1475 }
Amith Yamasani4f582632014-02-19 14:31:52 -08001476 }
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001477
1478 @Override
1479 public void onShortcutChanged(UserHandle user, String packageName,
1480 ParceledListSlice shortcuts) {
1481 if (DEBUG) {
1482 Log.d(TAG, "onShortcutChanged " + user.getIdentifier() + "," + packageName);
1483 }
1484 final List<ShortcutInfo> list = shortcuts.getList();
1485 synchronized (LauncherApps.this) {
1486 for (CallbackMessageHandler callback : mCallbacks) {
1487 callback.postOnShortcutChanged(packageName, user, list);
1488 }
1489 }
1490 }
Amith Yamasani4f582632014-02-19 14:31:52 -08001491 };
Kenny Guyb42c89b2014-07-28 19:20:07 +01001492
1493 private static class CallbackMessageHandler extends Handler {
1494 private static final int MSG_ADDED = 1;
1495 private static final int MSG_REMOVED = 2;
1496 private static final int MSG_CHANGED = 3;
1497 private static final int MSG_AVAILABLE = 4;
1498 private static final int MSG_UNAVAILABLE = 5;
Kenny Guy77242752016-01-15 13:29:06 +00001499 private static final int MSG_SUSPENDED = 6;
1500 private static final int MSG_UNSUSPENDED = 7;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001501 private static final int MSG_SHORTCUT_CHANGED = 8;
Kenny Guyb42c89b2014-07-28 19:20:07 +01001502
Kenny Guyf939dba2014-08-15 15:32:34 +01001503 private LauncherApps.Callback mCallback;
Kenny Guyb42c89b2014-07-28 19:20:07 +01001504
1505 private static class CallbackInfo {
1506 String[] packageNames;
1507 String packageName;
Suprabh Shukla19b41f32018-03-26 22:35:13 -07001508 Bundle launcherExtras;
Kenny Guyb42c89b2014-07-28 19:20:07 +01001509 boolean replacing;
1510 UserHandle user;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001511 List<ShortcutInfo> shortcuts;
Kenny Guyb42c89b2014-07-28 19:20:07 +01001512 }
1513
Kenny Guyf939dba2014-08-15 15:32:34 +01001514 public CallbackMessageHandler(Looper looper, LauncherApps.Callback callback) {
Kenny Guyb42c89b2014-07-28 19:20:07 +01001515 super(looper, null, true);
1516 mCallback = callback;
1517 }
1518
1519 @Override
1520 public void handleMessage(Message msg) {
1521 if (mCallback == null || !(msg.obj instanceof CallbackInfo)) {
1522 return;
1523 }
1524 CallbackInfo info = (CallbackInfo) msg.obj;
1525 switch (msg.what) {
1526 case MSG_ADDED:
1527 mCallback.onPackageAdded(info.packageName, info.user);
1528 break;
1529 case MSG_REMOVED:
1530 mCallback.onPackageRemoved(info.packageName, info.user);
1531 break;
1532 case MSG_CHANGED:
1533 mCallback.onPackageChanged(info.packageName, info.user);
1534 break;
1535 case MSG_AVAILABLE:
1536 mCallback.onPackagesAvailable(info.packageNames, info.user, info.replacing);
1537 break;
1538 case MSG_UNAVAILABLE:
1539 mCallback.onPackagesUnavailable(info.packageNames, info.user, info.replacing);
1540 break;
Kenny Guy77242752016-01-15 13:29:06 +00001541 case MSG_SUSPENDED:
Suprabh Shukla96212bc2018-04-10 15:04:51 -07001542 mCallback.onPackagesSuspended(info.packageNames, info.user, info.launcherExtras
1543 );
Kenny Guy77242752016-01-15 13:29:06 +00001544 break;
1545 case MSG_UNSUSPENDED:
1546 mCallback.onPackagesUnsuspended(info.packageNames, info.user);
1547 break;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001548 case MSG_SHORTCUT_CHANGED:
1549 mCallback.onShortcutsChanged(info.packageName, info.shortcuts, info.user);
1550 break;
Kenny Guyb42c89b2014-07-28 19:20:07 +01001551 }
1552 }
1553
1554 public void postOnPackageAdded(String packageName, UserHandle user) {
1555 CallbackInfo info = new CallbackInfo();
1556 info.packageName = packageName;
1557 info.user = user;
1558 obtainMessage(MSG_ADDED, info).sendToTarget();
1559 }
1560
1561 public void postOnPackageRemoved(String packageName, UserHandle user) {
1562 CallbackInfo info = new CallbackInfo();
1563 info.packageName = packageName;
1564 info.user = user;
1565 obtainMessage(MSG_REMOVED, info).sendToTarget();
1566 }
1567
1568 public void postOnPackageChanged(String packageName, UserHandle user) {
1569 CallbackInfo info = new CallbackInfo();
1570 info.packageName = packageName;
1571 info.user = user;
1572 obtainMessage(MSG_CHANGED, info).sendToTarget();
1573 }
1574
1575 public void postOnPackagesAvailable(String[] packageNames, UserHandle user,
1576 boolean replacing) {
1577 CallbackInfo info = new CallbackInfo();
1578 info.packageNames = packageNames;
1579 info.replacing = replacing;
1580 info.user = user;
1581 obtainMessage(MSG_AVAILABLE, info).sendToTarget();
1582 }
1583
1584 public void postOnPackagesUnavailable(String[] packageNames, UserHandle user,
1585 boolean replacing) {
1586 CallbackInfo info = new CallbackInfo();
1587 info.packageNames = packageNames;
1588 info.replacing = replacing;
1589 info.user = user;
1590 obtainMessage(MSG_UNAVAILABLE, info).sendToTarget();
1591 }
Kenny Guy77242752016-01-15 13:29:06 +00001592
Suprabh Shukla19b41f32018-03-26 22:35:13 -07001593 public void postOnPackagesSuspended(String[] packageNames, Bundle launcherExtras,
1594 UserHandle user) {
Kenny Guy77242752016-01-15 13:29:06 +00001595 CallbackInfo info = new CallbackInfo();
1596 info.packageNames = packageNames;
1597 info.user = user;
Suprabh Shukla19b41f32018-03-26 22:35:13 -07001598 info.launcherExtras = launcherExtras;
Kenny Guy77242752016-01-15 13:29:06 +00001599 obtainMessage(MSG_SUSPENDED, info).sendToTarget();
1600 }
1601
1602 public void postOnPackagesUnsuspended(String[] packageNames, UserHandle user) {
1603 CallbackInfo info = new CallbackInfo();
1604 info.packageNames = packageNames;
1605 info.user = user;
1606 obtainMessage(MSG_UNSUSPENDED, info).sendToTarget();
1607 }
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001608
1609 public void postOnShortcutChanged(String packageName, UserHandle user,
1610 List<ShortcutInfo> shortcuts) {
1611 CallbackInfo info = new CallbackInfo();
1612 info.packageName = packageName;
1613 info.user = user;
1614 info.shortcuts = shortcuts;
1615 obtainMessage(MSG_SHORTCUT_CHANGED, info).sendToTarget();
1616 }
Kenny Guyb42c89b2014-07-28 19:20:07 +01001617 }
Makoto Onuki2d895c32016-12-02 15:48:40 -08001618
1619 /**
Jon Miranda2b340a22019-01-25 14:03:49 -08001620 * Register a callback to watch for session lifecycle events in this user and managed profiles.
1621 * @param callback The callback to register.
1622 * @param executor {@link Executor} to handle the callbacks, cannot be null.
1623 *
1624 * @see PackageInstaller#registerSessionCallback(SessionCallback)
1625 */
1626 public void registerPackageInstallerSessionCallback(
1627 @NonNull @CallbackExecutor Executor executor, @NonNull SessionCallback callback) {
1628 if (executor == null) {
1629 throw new NullPointerException("Executor must not be null");
1630 }
1631
1632 synchronized (mDelegates) {
1633 final SessionCallbackDelegate delegate = new SessionCallbackDelegate(callback,
1634 executor);
1635 try {
1636 mService.registerPackageInstallerCallback(mContext.getPackageName(),
1637 delegate);
1638 } catch (RemoteException e) {
1639 throw e.rethrowFromSystemServer();
1640 }
1641 mDelegates.add(delegate);
1642 }
1643 }
1644
1645 /**
1646 * Unregisters a callback that was previously registered.
1647 *
1648 * @param callback The callback to unregister.
1649 * @see #registerPackageInstallerSessionCallback(Executor, SessionCallback)
1650 */
Jon Miranda93505982019-03-08 09:33:42 -08001651 public void unregisterPackageInstallerSessionCallback(@NonNull SessionCallback callback) {
Jon Miranda2b340a22019-01-25 14:03:49 -08001652 synchronized (mDelegates) {
1653 for (Iterator<SessionCallbackDelegate> i = mDelegates.iterator(); i.hasNext();) {
1654 final SessionCallbackDelegate delegate = i.next();
1655 if (delegate.mCallback == callback) {
1656 mPm.getPackageInstaller().unregisterSessionCallback(delegate.mCallback);
1657 i.remove();
1658 }
1659 }
1660 }
1661 }
1662
1663 /**
1664 * Return list of all known install sessions in this user and managed profiles, regardless
1665 * of the installer.
1666 *
1667 * @see PackageInstaller#getAllSessions()
1668 */
1669 public @NonNull List<SessionInfo> getAllPackageInstallerSessions() {
1670 try {
1671 return mService.getAllSessions(mContext.getPackageName()).getList();
1672 } catch (RemoteException e) {
1673 throw e.rethrowFromSystemServer();
1674 }
1675 }
1676
1677 /**
Mehdi Alizadeh9f680192020-01-16 18:09:24 -08001678 * Register a callback to watch for shortcut change events in this user and managed profiles.
1679 *
1680 * @param callback The callback to register.
1681 * @param query {@link ShortcutQuery} to match and filter the shortcut events. Only matching
1682 * shortcuts will be returned by the callback.
1683 * @param executor {@link Executor} to handle the callbacks. To dispatch callbacks to the main
1684 * thread of your application, you can use {@link android.content.Context#getMainExecutor()}.
1685 *
1686 * @hide
1687 */
1688 public void registerShortcutChangeCallback(@NonNull ShortcutChangeCallback callback,
1689 @NonNull ShortcutQuery query, @NonNull @CallbackExecutor Executor executor) {
1690 Objects.requireNonNull(callback, "Callback cannot be null");
1691 Objects.requireNonNull(query, "Query cannot be null");
1692 Objects.requireNonNull(executor, "Executor cannot be null");
1693
1694 synchronized (mShortcutChangeCallbacks) {
1695 final int callbackId = callback.hashCode();
1696 final Pair<Executor, ShortcutChangeCallback> state = new Pair<>(executor, callback);
1697 mShortcutChangeCallbacks.put(callbackId, state);
1698 try {
1699 mService.registerShortcutChangeCallback(mContext.getPackageName(),
Mehdi Alizadehae808ff2020-01-21 13:39:53 -08001700 query.mChangedSince, query.mPackage, query.mShortcutIds, query.mLocusIds,
1701 query.mActivity, query.mQueryFlags, new ShortcutChangeCallbackProxy(state),
1702 callbackId);
Mehdi Alizadeh9f680192020-01-16 18:09:24 -08001703 } catch (RemoteException e) {
1704 throw e.rethrowFromSystemServer();
1705 }
1706 }
1707 }
1708
1709 /**
1710 * Unregisters a callback that was previously registered.
1711 * @see #registerShortcutChangeCallback(ShortcutChangeCallback, ShortcutQuery, Executor)
1712 *
1713 * @param callback Callback to be unregistered.
1714 *
1715 * @hide
1716 */
1717 public void unregisterShortcutChangeCallback(@NonNull ShortcutChangeCallback callback) {
1718 Objects.requireNonNull(callback, "Callback cannot be null");
1719
1720 synchronized (mShortcutChangeCallbacks) {
1721 final int callbackId = callback.hashCode();
1722 if (mShortcutChangeCallbacks.containsKey(callbackId)) {
1723 mShortcutChangeCallbacks.remove(callbackId);
1724 try {
1725 mService.unregisterShortcutChangeCallback(mContext.getPackageName(),
1726 callbackId);
1727 } catch (RemoteException e) {
1728 throw e.rethrowFromSystemServer();
1729 }
1730 }
1731 }
1732 }
1733
1734 /**
Makoto Onuki2d895c32016-12-02 15:48:40 -08001735 * A helper method to extract a {@link PinItemRequest} set to
1736 * the {@link #EXTRA_PIN_ITEM_REQUEST} extra.
1737 */
1738 public PinItemRequest getPinItemRequest(Intent intent) {
1739 return intent.getParcelableExtra(EXTRA_PIN_ITEM_REQUEST);
1740 }
1741
1742 /**
Sunny Goyal7f7372a2017-01-24 11:53:54 -08001743 * Represents a "pin shortcut" or a "pin appwidget" request made by an app, which is sent with
1744 * an {@link #ACTION_CONFIRM_PIN_SHORTCUT} or {@link #ACTION_CONFIRM_PIN_APPWIDGET} intent
1745 * respectively to the default launcher app.
Makoto Onuki2d895c32016-12-02 15:48:40 -08001746 *
Makoto Onukia37ac3d2017-04-14 12:33:10 -07001747 * <h3>Request of the {@link #REQUEST_TYPE_SHORTCUT} type.
Makoto Onuki0c280712017-01-19 15:14:27 -08001748 *
Makoto Onukia37ac3d2017-04-14 12:33:10 -07001749 * <p>A {@link #REQUEST_TYPE_SHORTCUT} request represents a request to pin a
1750 * {@link ShortcutInfo}. If the launcher accepts a request, call {@link #accept()},
1751 * or {@link #accept(Bundle)} with a null or empty Bundle. No options are defined for
1752 * pin-shortcuts requests.
1753 *
1754 * <p>{@link #getShortcutInfo()} always returns a non-null {@link ShortcutInfo} for this type.
1755 *
1756 * <p>The launcher may receive a request with a {@link ShortcutInfo} that is already pinned, in
1757 * which case {@link ShortcutInfo#isPinned()} returns true. This means the user wants to create
1758 * another pinned shortcut for a shortcut that's already pinned. If the launcher accepts it,
1759 * {@link #accept()} must still be called even though the shortcut is already pinned, and
1760 * create a new pinned shortcut icon for it.
1761 *
1762 * <p>See also {@link ShortcutManager} for more details.
1763 *
1764 * <h3>Request of the {@link #REQUEST_TYPE_APPWIDGET} type.
1765 *
1766 * <p>A {@link #REQUEST_TYPE_SHORTCUT} request represents a request to pin a
1767 * an AppWidget. If the launcher accepts a request, call {@link #accept(Bundle)} with
1768 * the appwidget integer ID set to the
1769 * {@link android.appwidget.AppWidgetManager#EXTRA_APPWIDGET_ID} extra.
1770 *
1771 * <p>{@link #getAppWidgetProviderInfo(Context)} always returns a non-null
1772 * {@link AppWidgetProviderInfo} for this type.
1773 *
1774 * <p>See also {@link AppWidgetManager} for more details.
Sunny Goyal7f7372a2017-01-24 11:53:54 -08001775 *
Makoto Onuki2d895c32016-12-02 15:48:40 -08001776 * @see #EXTRA_PIN_ITEM_REQUEST
1777 * @see #getPinItemRequest(Intent)
1778 */
1779 public static final class PinItemRequest implements Parcelable {
1780
1781 /** This is a request to pin shortcut. */
1782 public static final int REQUEST_TYPE_SHORTCUT = 1;
1783
Sunny Goyal87a563e2017-01-01 19:42:45 -08001784 /** This is a request to pin app widget. */
1785 public static final int REQUEST_TYPE_APPWIDGET = 2;
1786
Makoto Onukif5663b12017-01-09 14:09:56 -08001787 /** @hide */
Jeff Sharkeyce8db992017-12-13 20:05:05 -07001788 @IntDef(prefix = { "REQUEST_TYPE_" }, value = {
1789 REQUEST_TYPE_SHORTCUT,
1790 REQUEST_TYPE_APPWIDGET
1791 })
Makoto Onuki2d895c32016-12-02 15:48:40 -08001792 @Retention(RetentionPolicy.SOURCE)
1793 public @interface RequestType {}
1794
1795 private final int mRequestType;
Makoto Onuki2d895c32016-12-02 15:48:40 -08001796 private final IPinItemRequest mInner;
1797
1798 /**
1799 * @hide
1800 */
Makoto Onuki8abba3a2017-02-24 11:34:54 -08001801 public PinItemRequest(IPinItemRequest inner, int type) {
Sunny Goyal87a563e2017-01-01 19:42:45 -08001802 mInner = inner;
Makoto Onuki8abba3a2017-02-24 11:34:54 -08001803 mRequestType = type;
Makoto Onuki2d895c32016-12-02 15:48:40 -08001804 }
1805
1806 /**
Makoto Onukia37ac3d2017-04-14 12:33:10 -07001807 * Represents the type of a request, which is one of the {@code REQUEST_TYPE_} constants.
1808 *
1809 * @return one of the {@code REQUEST_TYPE_} constants.
Makoto Onuki2d895c32016-12-02 15:48:40 -08001810 */
1811 @RequestType
1812 public int getRequestType() {
1813 return mRequestType;
1814 }
1815
1816 /**
Makoto Onukia37ac3d2017-04-14 12:33:10 -07001817 * {@link ShortcutInfo} sent by the requesting app.
1818 * Always non-null for a {@link #REQUEST_TYPE_SHORTCUT} request, and always null for a
1819 * different request type.
1820 *
1821 * @return requested {@link ShortcutInfo} when a request is of the
1822 * {@link #REQUEST_TYPE_SHORTCUT} type. Null otherwise.
Makoto Onuki2d895c32016-12-02 15:48:40 -08001823 */
1824 @Nullable
1825 public ShortcutInfo getShortcutInfo() {
Makoto Onuki8abba3a2017-02-24 11:34:54 -08001826 try {
1827 return mInner.getShortcutInfo();
1828 } catch (RemoteException e) {
1829 throw e.rethrowAsRuntimeException();
1830 }
Makoto Onuki2d895c32016-12-02 15:48:40 -08001831 }
1832
1833 /**
Makoto Onukia37ac3d2017-04-14 12:33:10 -07001834 * {@link AppWidgetProviderInfo} sent by the requesting app.
1835 * Always non-null for a {@link #REQUEST_TYPE_APPWIDGET} request, and always null for a
1836 * different request type.
1837 *
Sunny Goyale7712ad2018-03-08 11:23:06 -08001838 * <p>Launcher should not show any configuration activity associated with the provider, and
1839 * assume that the widget is already fully configured. Upon accepting the widget, it should
1840 * pass the widgetId in {@link #accept(Bundle)}.
1841 *
Makoto Onukia37ac3d2017-04-14 12:33:10 -07001842 * @return requested {@link AppWidgetProviderInfo} when a request is of the
1843 * {@link #REQUEST_TYPE_APPWIDGET} type. Null otherwise.
Sunny Goyal87a563e2017-01-01 19:42:45 -08001844 */
1845 @Nullable
Sunny Goyal970d4b42017-01-19 15:07:36 -08001846 public AppWidgetProviderInfo getAppWidgetProviderInfo(Context context) {
Makoto Onuki8abba3a2017-02-24 11:34:54 -08001847 try {
1848 final AppWidgetProviderInfo info = mInner.getAppWidgetProviderInfo();
1849 if (info == null) {
1850 return null;
1851 }
Sunny Goyal970d4b42017-01-19 15:07:36 -08001852 info.updateDimensions(context.getResources().getDisplayMetrics());
1853 return info;
Makoto Onuki8abba3a2017-02-24 11:34:54 -08001854 } catch (RemoteException e) {
1855 throw e.rethrowAsRuntimeException();
Sunny Goyal970d4b42017-01-19 15:07:36 -08001856 }
Sunny Goyal87a563e2017-01-01 19:42:45 -08001857 }
1858
1859 /**
Sunny Goyal4ad6b572017-02-28 11:11:51 -08001860 * Any extras sent by the requesting app.
Makoto Onukia37ac3d2017-04-14 12:33:10 -07001861 *
1862 * @return For a shortcut request, this method always return null. For an AppWidget
1863 * request, this method returns the extras passed to the
1864 * {@link android.appwidget.AppWidgetManager#requestPinAppWidget(
1865 * ComponentName, Bundle, PendingIntent)} API. See {@link AppWidgetManager} for details.
Sunny Goyal4ad6b572017-02-28 11:11:51 -08001866 */
1867 @Nullable
1868 public Bundle getExtras() {
1869 try {
1870 return mInner.getExtras();
1871 } catch (RemoteException e) {
1872 throw e.rethrowAsRuntimeException();
1873 }
1874 }
1875
1876 /**
Makoto Onukia37ac3d2017-04-14 12:33:10 -07001877 * Return whether a request is still valid.
1878 *
1879 * @return {@code TRUE} if a request is valid and {@link #accept(Bundle)} may be called.
Makoto Onuki2d895c32016-12-02 15:48:40 -08001880 */
1881 public boolean isValid() {
1882 try {
1883 return mInner.isValid();
1884 } catch (RemoteException e) {
1885 return false;
1886 }
1887 }
1888
1889 /**
1890 * Called by the receiving launcher app when the user accepts the request.
Makoto Onukia37ac3d2017-04-14 12:33:10 -07001891 *
1892 * @param options must be set for a {@link #REQUEST_TYPE_APPWIDGET} request.
1893 *
1894 * @return {@code TRUE} if the shortcut or the AppWidget has actually been pinned.
1895 * {@code FALSE} if the item hasn't been pinned, for example, because the request had
1896 * already been canceled, in which case the launcher must not pin the requested item.
Makoto Onuki2d895c32016-12-02 15:48:40 -08001897 */
1898 public boolean accept(@Nullable Bundle options) {
1899 try {
1900 return mInner.accept(options);
1901 } catch (RemoteException e) {
1902 throw e.rethrowFromSystemServer();
1903 }
1904 }
1905
1906 /**
Makoto Onukia37ac3d2017-04-14 12:33:10 -07001907 * Called by the receiving launcher app when the user accepts the request, with no options.
1908 *
1909 * @return {@code TRUE} if the shortcut or the AppWidget has actually been pinned.
1910 * {@code FALSE} if the item hasn't been pinned, for example, because the request had
1911 * already been canceled, in which case the launcher must not pin the requested item.
Makoto Onuki2d895c32016-12-02 15:48:40 -08001912 */
1913 public boolean accept() {
1914 return accept(/* options= */ null);
1915 }
1916
1917 private PinItemRequest(Parcel source) {
1918 final ClassLoader cl = getClass().getClassLoader();
1919
1920 mRequestType = source.readInt();
Makoto Onuki2d895c32016-12-02 15:48:40 -08001921 mInner = IPinItemRequest.Stub.asInterface(source.readStrongBinder());
1922 }
1923
1924 @Override
1925 public void writeToParcel(Parcel dest, int flags) {
1926 dest.writeInt(mRequestType);
Makoto Onuki2d895c32016-12-02 15:48:40 -08001927 dest.writeStrongBinder(mInner.asBinder());
1928 }
1929
Jeff Sharkey9e8f83d2019-02-28 12:06:45 -07001930 public static final @android.annotation.NonNull Creator<PinItemRequest> CREATOR =
Makoto Onuki2d895c32016-12-02 15:48:40 -08001931 new Creator<PinItemRequest>() {
1932 public PinItemRequest createFromParcel(Parcel source) {
1933 return new PinItemRequest(source);
1934 }
1935 public PinItemRequest[] newArray(int size) {
1936 return new PinItemRequest[size];
1937 }
1938 };
1939
1940 @Override
1941 public int describeContents() {
1942 return 0;
1943 }
1944 }
Varun Shah2546cef2019-01-11 15:50:54 -08001945
1946 /**
1947 * A class that encapsulates information about the usage limit set for an app or
1948 * a group of apps.
1949 *
Varun Shah9c6f72b2019-01-25 21:13:56 -08001950 * <p>The launcher can query specifics about the usage limit such as how much usage time
1951 * the limit has and how much of the total usage time is remaining via the APIs available
1952 * in this class.
Varun Shah2546cef2019-01-11 15:50:54 -08001953 *
1954 * @see #getAppUsageLimit(String, UserHandle)
Sunny Goyalbeee1972019-03-29 11:38:16 -07001955 * @hide
Varun Shah2546cef2019-01-11 15:50:54 -08001956 */
Sunny Goyalbeee1972019-03-29 11:38:16 -07001957 @SystemApi
Varun Shah2546cef2019-01-11 15:50:54 -08001958 public static final class AppUsageLimit implements Parcelable {
Varun Shah2546cef2019-01-11 15:50:54 -08001959 private final long mTotalUsageLimit;
1960 private final long mUsageRemaining;
1961
1962 /** @hide */
Varun Shah9c6f72b2019-01-25 21:13:56 -08001963 public AppUsageLimit(long totalUsageLimit, long usageRemaining) {
Varun Shah2546cef2019-01-11 15:50:54 -08001964 this.mTotalUsageLimit = totalUsageLimit;
1965 this.mUsageRemaining = usageRemaining;
1966 }
1967
1968 /**
Varun Shah2546cef2019-01-11 15:50:54 -08001969 * Returns the total usage limit in milliseconds set for an app or a group of apps.
1970 *
1971 * @return the total usage limit in milliseconds
1972 */
1973 public long getTotalUsageLimit() {
1974 return mTotalUsageLimit;
1975 }
1976
1977 /**
1978 * Returns the usage remaining in milliseconds for an app or the group of apps
1979 * this limit refers to.
1980 *
1981 * @return the usage remaining in milliseconds
1982 */
1983 public long getUsageRemaining() {
1984 return mUsageRemaining;
1985 }
1986
1987 private AppUsageLimit(Parcel source) {
Varun Shah2546cef2019-01-11 15:50:54 -08001988 mTotalUsageLimit = source.readLong();
1989 mUsageRemaining = source.readLong();
1990 }
1991
Jeff Sharkey9e8f83d2019-02-28 12:06:45 -07001992 public static final @android.annotation.NonNull Creator<AppUsageLimit> CREATOR = new Creator<AppUsageLimit>() {
Varun Shah2546cef2019-01-11 15:50:54 -08001993 @Override
1994 public AppUsageLimit createFromParcel(Parcel source) {
1995 return new AppUsageLimit(source);
1996 }
1997
1998 @Override
1999 public AppUsageLimit[] newArray(int size) {
2000 return new AppUsageLimit[size];
2001 }
2002 };
2003
2004 @Override
2005 public int describeContents() {
2006 return 0;
2007 }
2008
2009 @Override
2010 public void writeToParcel(Parcel dest, int flags) {
Varun Shah2546cef2019-01-11 15:50:54 -08002011 dest.writeLong(mTotalUsageLimit);
2012 dest.writeLong(mUsageRemaining);
2013 }
2014 }
Amith Yamasani4f582632014-02-19 14:31:52 -08002015}