blob: 954deac97d6dab531701c5b58585a052601a2cb3 [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;
Makoto Onukib1588c02017-10-12 15:11:45 -070025import android.annotation.SystemService;
Makoto Onuki5ba0d3e2016-04-11 14:03:46 -070026import android.annotation.TestApi;
Mathew Inwood5c0d3542018-08-14 13:54:31 +010027import android.annotation.UnsupportedAppUsage;
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;
Makoto Onuki83f6d2d2016-07-11 14:30:19 -070031import android.content.ActivityNotFoundException;
Amith Yamasani4f582632014-02-19 14:31:52 -080032import android.content.ComponentName;
33import android.content.Context;
34import android.content.Intent;
Sunny Goyala6be88a2017-01-12 16:27:58 -080035import android.content.IntentSender;
Jon Miranda2b340a22019-01-25 14:03:49 -080036import android.content.pm.PackageInstaller.SessionCallback;
37import android.content.pm.PackageInstaller.SessionCallbackDelegate;
38import android.content.pm.PackageInstaller.SessionInfo;
Kenny Guy77242752016-01-15 13:29:06 +000039import android.content.pm.PackageManager.ApplicationInfoFlags;
Makoto Onuki04b9aab2016-05-23 17:13:30 -070040import android.content.pm.PackageManager.NameNotFoundException;
41import android.content.res.Resources;
42import android.graphics.Bitmap;
43import android.graphics.BitmapFactory;
Amith Yamasani4f582632014-02-19 14:31:52 -080044import android.graphics.Rect;
Makoto Onukib1588c02017-10-12 15:11:45 -070045import android.graphics.drawable.AdaptiveIconDrawable;
Makoto Onuki04b9aab2016-05-23 17:13:30 -070046import android.graphics.drawable.BitmapDrawable;
Makoto Onuki20c95f82016-05-11 16:51:01 -070047import android.graphics.drawable.Drawable;
Makoto Onuki2d895c32016-12-02 15:48:40 -080048import android.graphics.drawable.Icon;
Mathew Inwood8c854f82018-09-14 12:35:36 +010049import android.os.Build;
Amith Yamasani4f582632014-02-19 14:31:52 -080050import android.os.Bundle;
Kenny Guyb42c89b2014-07-28 19:20:07 +010051import android.os.Handler;
52import android.os.Looper;
53import android.os.Message;
Makoto Onuki2d895c32016-12-02 15:48:40 -080054import android.os.Parcel;
Makoto Onuki6f7362d92016-03-04 13:39:41 -080055import android.os.ParcelFileDescriptor;
Makoto Onuki2d895c32016-12-02 15:48:40 -080056import android.os.Parcelable;
Amith Yamasani4f582632014-02-19 14:31:52 -080057import android.os.RemoteException;
Makoto Onuki5ba0d3e2016-04-11 14:03:46 -070058import android.os.ServiceManager;
Amith Yamasani4f582632014-02-19 14:31:52 -080059import android.os.UserHandle;
Amith Yamasanie781c812014-05-28 15:28:18 -070060import android.os.UserManager;
Makoto Onuki04b9aab2016-05-23 17:13:30 -070061import android.util.DisplayMetrics;
Amith Yamasani4f582632014-02-19 14:31:52 -080062import android.util.Log;
63
Makoto Onuki7c7fbf62017-04-14 11:03:56 -070064import com.android.internal.util.Preconditions;
65
Makoto Onuki04b9aab2016-05-23 17:13:30 -070066import java.io.IOException;
Makoto Onuki6f7362d92016-03-04 13:39:41 -080067import java.lang.annotation.Retention;
68import java.lang.annotation.RetentionPolicy;
Amith Yamasani4f582632014-02-19 14:31:52 -080069import java.util.ArrayList;
Makoto Onukib6d35232016-04-04 15:57:17 -070070import java.util.Arrays;
Amith Yamasani4f582632014-02-19 14:31:52 -080071import java.util.Collections;
Jon Miranda2b340a22019-01-25 14:03:49 -080072import java.util.Iterator;
Amith Yamasani4f582632014-02-19 14:31:52 -080073import java.util.List;
Jon Miranda2b340a22019-01-25 14:03:49 -080074import java.util.concurrent.Executor;
Amith Yamasani4f582632014-02-19 14:31:52 -080075
76/**
77 * Class for retrieving a list of launchable activities for the current user and any associated
Makoto Onukiaecbd032017-01-19 12:11:11 -080078 * managed profiles that are visible to the current user, which can be retrieved with
79 * {@link #getProfiles}. This is mainly for use by launchers.
80 *
81 * Apps can be queried for each user profile.
Amith Yamasani4f582632014-02-19 14:31:52 -080082 * Since the PackageManager will not deliver package broadcasts for other profiles, you can register
83 * for package changes here.
Amith Yamasanie781c812014-05-28 15:28:18 -070084 * <p>
85 * To watch for managed profiles being added or removed, register for the following broadcasts:
86 * {@link Intent#ACTION_MANAGED_PROFILE_ADDED} and {@link Intent#ACTION_MANAGED_PROFILE_REMOVED}.
87 * <p>
Makoto Onukiaecbd032017-01-19 12:11:11 -080088 * Note as of Android O, apps on a managed profile are no longer allowed to access apps on the
89 * main profile. Apps can only access profiles returned by {@link #getProfiles()}.
Amith Yamasani4f582632014-02-19 14:31:52 -080090 */
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -060091@SystemService(Context.LAUNCHER_APPS_SERVICE)
Amith Yamasani4f582632014-02-19 14:31:52 -080092public class LauncherApps {
93
94 static final String TAG = "LauncherApps";
95 static final boolean DEBUG = false;
96
Makoto Onuki2d895c32016-12-02 15:48:40 -080097 /**
98 * Activity Action: For the default launcher to show the confirmation dialog to create
99 * a pinned shortcut.
100 *
101 * <p>See the {@link ShortcutManager} javadoc for details.
102 *
103 * <p>
104 * Use {@link #getPinItemRequest(Intent)} to get a {@link PinItemRequest} object,
105 * and call {@link PinItemRequest#accept(Bundle)}
106 * if the user accepts. If the user doesn't accept, no further action is required.
107 *
108 * @see #EXTRA_PIN_ITEM_REQUEST
109 */
110 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
Sunny Goyal7f7372a2017-01-24 11:53:54 -0800111 public static final String ACTION_CONFIRM_PIN_SHORTCUT =
112 "android.content.pm.action.CONFIRM_PIN_SHORTCUT";
Makoto Onuki2d895c32016-12-02 15:48:40 -0800113
114 /**
Sunny Goyal7f7372a2017-01-24 11:53:54 -0800115 * Activity Action: For the default launcher to show the confirmation dialog to create
116 * a pinned app widget.
117 *
118 * <p>See the {@link android.appwidget.AppWidgetManager#requestPinAppWidget} javadoc for
119 * details.
120 *
121 * <p>
122 * Use {@link #getPinItemRequest(Intent)} to get a {@link PinItemRequest} object,
123 * and call {@link PinItemRequest#accept(Bundle)}
124 * if the user accepts. If the user doesn't accept, no further action is required.
125 *
126 * @see #EXTRA_PIN_ITEM_REQUEST
127 */
128 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
129 public static final String ACTION_CONFIRM_PIN_APPWIDGET =
130 "android.content.pm.action.CONFIRM_PIN_APPWIDGET";
131
132 /**
133 * An extra for {@link #ACTION_CONFIRM_PIN_SHORTCUT} &amp; {@link #ACTION_CONFIRM_PIN_APPWIDGET}
134 * containing a {@link PinItemRequest} of appropriate type asked to pin.
Makoto Onuki2d895c32016-12-02 15:48:40 -0800135 *
136 * <p>A helper function {@link #getPinItemRequest(Intent)} can be used
137 * instead of using this constant directly.
138 *
Sunny Goyal7f7372a2017-01-24 11:53:54 -0800139 * @see #ACTION_CONFIRM_PIN_SHORTCUT
140 * @see #ACTION_CONFIRM_PIN_APPWIDGET
Makoto Onuki2d895c32016-12-02 15:48:40 -0800141 */
142 public static final String EXTRA_PIN_ITEM_REQUEST =
143 "android.content.pm.extra.PIN_ITEM_REQUEST";
144
Makoto Onukide3c16c2017-01-26 11:39:31 -0800145 private final Context mContext;
Mathew Inwood8c854f82018-09-14 12:35:36 +0100146 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
Makoto Onukide3c16c2017-01-26 11:39:31 -0800147 private final ILauncherApps mService;
Mathew Inwood5c0d3542018-08-14 13:54:31 +0100148 @UnsupportedAppUsage
Makoto Onukide3c16c2017-01-26 11:39:31 -0800149 private final PackageManager mPm;
150 private final UserManager mUserManager;
Amith Yamasani4f582632014-02-19 14:31:52 -0800151
Jon Miranda2b340a22019-01-25 14:03:49 -0800152 private final List<CallbackMessageHandler> mCallbacks = new ArrayList<>();
153 private final List<SessionCallbackDelegate> mDelegates = new ArrayList<>();
Kenny Guyc01545372014-06-16 14:17:26 +0100154
155 /**
156 * Callbacks for package changes to this and related managed profiles.
157 */
Kenny Guyf939dba2014-08-15 15:32:34 +0100158 public static abstract class Callback {
Kenny Guyc01545372014-06-16 14:17:26 +0100159 /**
160 * Indicates that a package was removed from the specified profile.
161 *
Kenny Guyb42c89b2014-07-28 19:20:07 +0100162 * If a package is removed while being updated onPackageChanged will be
163 * called instead.
164 *
Kenny Guyc01545372014-06-16 14:17:26 +0100165 * @param packageName The name of the package that was removed.
166 * @param user The UserHandle of the profile that generated the change.
167 */
168 abstract public void onPackageRemoved(String packageName, UserHandle user);
169
170 /**
171 * Indicates that a package was added to the specified profile.
172 *
Kenny Guyb42c89b2014-07-28 19:20:07 +0100173 * If a package is added while being updated then onPackageChanged will be
174 * called instead.
175 *
Kenny Guyc01545372014-06-16 14:17:26 +0100176 * @param packageName The name of the package that was added.
177 * @param user The UserHandle of the profile that generated the change.
178 */
179 abstract public void onPackageAdded(String packageName, UserHandle user);
180
181 /**
182 * Indicates that a package was modified in the specified profile.
Kenny Guyb42c89b2014-07-28 19:20:07 +0100183 * This can happen, for example, when the package is updated or when
184 * one or more components are enabled or disabled.
Kenny Guyc01545372014-06-16 14:17:26 +0100185 *
186 * @param packageName The name of the package that has changed.
187 * @param user The UserHandle of the profile that generated the change.
188 */
189 abstract public void onPackageChanged(String packageName, UserHandle user);
190
191 /**
192 * Indicates that one or more packages have become available. For
193 * example, this can happen when a removable storage card has
194 * reappeared.
195 *
196 * @param packageNames The names of the packages that have become
197 * available.
198 * @param user The UserHandle of the profile that generated the change.
199 * @param replacing Indicates whether these packages are replacing
200 * existing ones.
201 */
202 abstract public void onPackagesAvailable(String[] packageNames, UserHandle user,
203 boolean replacing);
204
205 /**
206 * Indicates that one or more packages have become unavailable. For
207 * example, this can happen when a removable storage card has been
208 * removed.
209 *
210 * @param packageNames The names of the packages that have become
211 * unavailable.
212 * @param user The UserHandle of the profile that generated the change.
213 * @param replacing Indicates whether the packages are about to be
214 * replaced with new versions.
215 */
216 abstract public void onPackagesUnavailable(String[] packageNames, UserHandle user,
217 boolean replacing);
Kenny Guy77242752016-01-15 13:29:06 +0000218
219 /**
220 * Indicates that one or more packages have been suspended. For
221 * example, this can happen when a Device Administrator suspends
222 * an applicaton.
223 *
Suprabh Shukla19b41f32018-03-26 22:35:13 -0700224 * <p>Note: On devices running {@link android.os.Build.VERSION_CODES#P Android P} or higher,
Suprabh Shukla96212bc2018-04-10 15:04:51 -0700225 * any apps that override {@link #onPackagesSuspended(String[], UserHandle, Bundle)} will
Suprabh Shukla19b41f32018-03-26 22:35:13 -0700226 * not receive this callback.
227 *
Kenny Guy77242752016-01-15 13:29:06 +0000228 * @param packageNames The names of the packages that have just been
229 * suspended.
230 * @param user The UserHandle of the profile that generated the change.
231 */
232 public void onPackagesSuspended(String[] packageNames, UserHandle user) {
233 }
234
235 /**
Suprabh Shukla19b41f32018-03-26 22:35:13 -0700236 * Indicates that one or more packages have been suspended. A device administrator or an app
237 * with {@code android.permission.SUSPEND_APPS} can do this.
238 *
Suprabh Shukla96212bc2018-04-10 15:04:51 -0700239 * <p>A suspending app with the permission {@code android.permission.SUSPEND_APPS} can
240 * optionally provide a {@link Bundle} of extra information that it deems helpful for the
241 * launcher to handle the suspended state of these packages. The contents of this
Suprabh Shukla3e03ab92018-04-11 16:03:49 -0700242 * {@link Bundle} are supposed to be a contract between the suspending app and the launcher.
Suprabh Shukla19b41f32018-03-26 22:35:13 -0700243 *
Suprabh Shukla96212bc2018-04-10 15:04:51 -0700244 * @param packageNames The names of the packages that have just been suspended.
245 * @param user the user for which the given packages were suspended.
246 * @param launcherExtras A {@link Bundle} of extras for the launcher, if provided to the
247 * system, {@code null} otherwise.
Suprabh Shukla19b41f32018-03-26 22:35:13 -0700248 * @see PackageManager#isPackageSuspended()
249 * @see #getSuspendedPackageLauncherExtras(String, UserHandle)
250 */
Suprabh Shukla96212bc2018-04-10 15:04:51 -0700251 public void onPackagesSuspended(String[] packageNames, UserHandle user,
252 @Nullable Bundle launcherExtras) {
Suprabh Shukla19b41f32018-03-26 22:35:13 -0700253 onPackagesSuspended(packageNames, user);
254 }
255
256 /**
Kenny Guy77242752016-01-15 13:29:06 +0000257 * Indicates that one or more packages have been unsuspended. For
258 * example, this can happen when a Device Administrator unsuspends
259 * an applicaton.
260 *
261 * @param packageNames The names of the packages that have just been
262 * unsuspended.
263 * @param user The UserHandle of the profile that generated the change.
264 */
265 public void onPackagesUnsuspended(String[] packageNames, UserHandle user) {
266 }
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800267
268 /**
Makoto Onukife9c9662016-07-25 15:12:23 -0700269 * Indicates that one or more shortcuts of any kind (dynamic, pinned, or manifest)
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800270 * have been added, updated or removed.
271 *
Makoto Onuki2d5b4652016-03-11 16:09:54 -0800272 * <p>Only the applications that are allowed to access the shortcut information,
273 * as defined in {@link #hasShortcutHostPermission()}, will receive it.
274 *
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800275 * @param packageName The name of the package that has the shortcuts.
Makoto Onukife9c9662016-07-25 15:12:23 -0700276 * @param shortcuts All shortcuts from the package (dynamic, manifest and/or pinned).
277 * Only "key" information will be provided, as defined in
Makoto Onuki4d6b87f2016-06-17 13:47:40 -0700278 * {@link ShortcutInfo#hasKeyFieldsOnly()}.
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800279 * @param user The UserHandle of the profile that generated the change.
Makoto Onuki4a910962016-07-07 13:57:34 -0700280 *
281 * @see ShortcutManager
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800282 */
283 public void onShortcutsChanged(@NonNull String packageName,
284 @NonNull List<ShortcutInfo> shortcuts, @NonNull UserHandle user) {
285 }
286 }
287
288 /**
289 * Represents a query passed to {@link #getShortcuts(ShortcutQuery, UserHandle)}.
290 */
291 public static class ShortcutQuery {
292 /**
293 * Include dynamic shortcuts in the result.
294 */
Makoto Onukib5a012f2016-06-21 11:13:53 -0700295 public static final int FLAG_MATCH_DYNAMIC = 1 << 0;
296
297 /** @hide kept for unit tests */
298 @Deprecated
299 public static final int FLAG_GET_DYNAMIC = FLAG_MATCH_DYNAMIC;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800300
301 /**
302 * Include pinned shortcuts in the result.
Makoto Onuki88b4dcc2017-12-07 15:53:56 -0800303 *
304 * <p>If you are the selected assistant app, and wishes to fetch all shortcuts that the
305 * user owns on the launcher (or by other launchers, in case the user has multiple), use
306 * {@link #FLAG_MATCH_PINNED_BY_ANY_LAUNCHER} instead.
307 *
308 * <p>If you're a regular launcher app, there's no way to get shortcuts pinned by other
309 * launchers, and {@link #FLAG_MATCH_PINNED_BY_ANY_LAUNCHER} will be ignored. So use this
310 * flag to get own pinned shortcuts.
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800311 */
Makoto Onukib5a012f2016-06-21 11:13:53 -0700312 public static final int FLAG_MATCH_PINNED = 1 << 1;
313
314 /** @hide kept for unit tests */
315 @Deprecated
316 public static final int FLAG_GET_PINNED = FLAG_MATCH_PINNED;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800317
318 /**
Makoto Onuki22fcc682016-05-17 14:52:19 -0700319 * Include manifest shortcuts in the result.
320 */
Makoto Onukib5a012f2016-06-21 11:13:53 -0700321 public static final int FLAG_MATCH_MANIFEST = 1 << 3;
322
323 /** @hide kept for unit tests */
324 @Deprecated
325 public static final int FLAG_GET_MANIFEST = FLAG_MATCH_MANIFEST;
Makoto Onuki22fcc682016-05-17 14:52:19 -0700326
Hakan Seyalioglu58fc95d2016-12-13 15:23:22 -0800327 /**
Makoto Onuki35559d62017-11-06 16:26:32 -0800328 * Include all pinned shortcuts by any launchers, not just by the caller,
Makoto Onuki634cecb2017-10-13 17:10:48 -0700329 * in the result.
Makoto Onuki35559d62017-11-06 16:26:32 -0800330 *
Makoto Onuki88b4dcc2017-12-07 15:53:56 -0800331 * <p>The caller must be the selected assistant app to use this flag, or have the system
Makoto Onuki35559d62017-11-06 16:26:32 -0800332 * {@code ACCESS_SHORTCUTS} permission.
Makoto Onuki88b4dcc2017-12-07 15:53:56 -0800333 *
334 * <p>If you are the selected assistant app, and wishes to fetch all shortcuts that the
335 * user owns on the launcher (or by other launchers, in case the user has multiple), use
336 * {@link #FLAG_MATCH_PINNED_BY_ANY_LAUNCHER} instead.
337 *
338 * <p>If you're a regular launcher app (or any app that's not the selected assistant app)
339 * then this flag will be ignored.
Makoto Onuki634cecb2017-10-13 17:10:48 -0700340 */
Makoto Onuki35559d62017-11-06 16:26:32 -0800341 public static final int FLAG_MATCH_PINNED_BY_ANY_LAUNCHER = 1 << 10;
Makoto Onuki634cecb2017-10-13 17:10:48 -0700342
343 /**
344 * FLAG_MATCH_DYNAMIC | FLAG_MATCH_PINNED | FLAG_MATCH_MANIFEST
Hakan Seyalioglu58fc95d2016-12-13 15:23:22 -0800345 * @hide
346 */
Makoto Onukib5a012f2016-06-21 11:13:53 -0700347 public static final int FLAG_MATCH_ALL_KINDS =
Makoto Onuki634cecb2017-10-13 17:10:48 -0700348 FLAG_MATCH_DYNAMIC | FLAG_MATCH_PINNED | FLAG_MATCH_MANIFEST;
349
350 /**
351 * FLAG_MATCH_DYNAMIC | FLAG_MATCH_PINNED | FLAG_MATCH_MANIFEST | FLAG_MATCH_ALL_PINNED
352 * @hide
353 */
354 public static final int FLAG_MATCH_ALL_KINDS_WITH_ALL_PINNED =
Makoto Onuki35559d62017-11-06 16:26:32 -0800355 FLAG_MATCH_ALL_KINDS | FLAG_MATCH_PINNED_BY_ANY_LAUNCHER;
Makoto Onuki4d6b87f2016-06-17 13:47:40 -0700356
Makoto Onukib5a012f2016-06-21 11:13:53 -0700357 /** @hide kept for unit tests */
358 @Deprecated
359 public static final int FLAG_GET_ALL_KINDS = FLAG_MATCH_ALL_KINDS;
360
Makoto Onuki22fcc682016-05-17 14:52:19 -0700361 /**
Makoto Onukife9c9662016-07-25 15:12:23 -0700362 * Requests "key" fields only. See {@link ShortcutInfo#hasKeyFieldsOnly()}'s javadoc to
363 * see which fields fields "key".
364 * This allows quicker access to shortcut information in order to
365 * determine whether the caller's in-memory cache needs to be updated.
Makoto Onuki4a910962016-07-07 13:57:34 -0700366 *
Makoto Onukife9c9662016-07-25 15:12:23 -0700367 * <p>Typically, launcher applications cache all or most shortcut information
368 * in memory in order to show shortcuts without a delay.
369 *
370 * When a given launcher application wants to update its cache, such as when its process
371 * restarts, it can fetch shortcut information with this flag.
372 * The application can then check {@link ShortcutInfo#getLastChangedTimestamp()} for each
373 * shortcut, fetching a shortcut's non-key information only if that shortcut has been
374 * updated.
Makoto Onuki4a910962016-07-07 13:57:34 -0700375 *
376 * @see ShortcutManager
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800377 */
378 public static final int FLAG_GET_KEY_FIELDS_ONLY = 1 << 2;
379
380 /** @hide */
Jeff Sharkeyce8db992017-12-13 20:05:05 -0700381 @IntDef(flag = true, prefix = { "FLAG_" }, value = {
382 FLAG_MATCH_DYNAMIC,
383 FLAG_MATCH_PINNED,
384 FLAG_MATCH_MANIFEST,
385 FLAG_GET_KEY_FIELDS_ONLY,
386 FLAG_MATCH_MANIFEST,
387 })
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800388 @Retention(RetentionPolicy.SOURCE)
389 public @interface QueryFlags {}
390
391 long mChangedSince;
392
393 @Nullable
394 String mPackage;
395
396 @Nullable
Makoto Onukiabe84422016-04-07 09:41:19 -0700397 List<String> mShortcutIds;
398
399 @Nullable
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800400 ComponentName mActivity;
401
402 @QueryFlags
403 int mQueryFlags;
404
405 public ShortcutQuery() {
406 }
407
408 /**
Makoto Onukife9c9662016-07-25 15:12:23 -0700409 * If non-zero, returns only shortcuts that have been added or updated
410 * since the given timestamp, expressed in milliseconds since the Epoch&mdash;see
411 * {@link System#currentTimeMillis()}.
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800412 */
Makoto Onuki22fcc682016-05-17 14:52:19 -0700413 public ShortcutQuery setChangedSince(long changedSince) {
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800414 mChangedSince = changedSince;
Makoto Onuki22fcc682016-05-17 14:52:19 -0700415 return this;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800416 }
417
418 /**
419 * If non-null, returns only shortcuts from the package.
420 */
Makoto Onuki22fcc682016-05-17 14:52:19 -0700421 public ShortcutQuery setPackage(@Nullable String packageName) {
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800422 mPackage = packageName;
Makoto Onuki22fcc682016-05-17 14:52:19 -0700423 return this;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800424 }
425
426 /**
Makoto Onukiabe84422016-04-07 09:41:19 -0700427 * If non-null, return only the specified shortcuts by ID. When setting this field,
Makoto Onuki4a910962016-07-07 13:57:34 -0700428 * a package name must also be set with {@link #setPackage}.
Makoto Onukiabe84422016-04-07 09:41:19 -0700429 */
Makoto Onuki22fcc682016-05-17 14:52:19 -0700430 public ShortcutQuery setShortcutIds(@Nullable List<String> shortcutIds) {
Makoto Onukiabe84422016-04-07 09:41:19 -0700431 mShortcutIds = shortcutIds;
Makoto Onuki22fcc682016-05-17 14:52:19 -0700432 return this;
Makoto Onukiabe84422016-04-07 09:41:19 -0700433 }
434
435 /**
Makoto Onuki22fcc682016-05-17 14:52:19 -0700436 * If non-null, returns only shortcuts associated with the activity; i.e.
437 * {@link ShortcutInfo}s whose {@link ShortcutInfo#getActivity()} are equal
438 * to {@code activity}.
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800439 */
Makoto Onuki22fcc682016-05-17 14:52:19 -0700440 public ShortcutQuery setActivity(@Nullable ComponentName activity) {
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800441 mActivity = activity;
Makoto Onuki22fcc682016-05-17 14:52:19 -0700442 return this;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800443 }
444
Hakan Seyalioglu58fc95d2016-12-13 15:23:22 -0800445 /**
Makoto Onukife9c9662016-07-25 15:12:23 -0700446 * Set query options. At least one of the {@code MATCH} flags should be set. Otherwise,
447 * no shortcuts will be returned.
Makoto Onuki4a910962016-07-07 13:57:34 -0700448 *
Makoto Onukife9c9662016-07-25 15:12:23 -0700449 * <ul>
450 * <li>{@link #FLAG_MATCH_DYNAMIC}
451 * <li>{@link #FLAG_MATCH_PINNED}
452 * <li>{@link #FLAG_MATCH_MANIFEST}
453 * <li>{@link #FLAG_GET_KEY_FIELDS_ONLY}
454 * </ul>
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800455 */
Makoto Onuki22fcc682016-05-17 14:52:19 -0700456 public ShortcutQuery setQueryFlags(@QueryFlags int queryFlags) {
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800457 mQueryFlags = queryFlags;
Makoto Onuki22fcc682016-05-17 14:52:19 -0700458 return this;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800459 }
Kenny Guyc01545372014-06-16 14:17:26 +0100460 }
Amith Yamasani4f582632014-02-19 14:31:52 -0800461
Amith Yamasani4f582632014-02-19 14:31:52 -0800462 /** @hide */
463 public LauncherApps(Context context, ILauncherApps service) {
464 mContext = context;
465 mService = service;
Amith Yamasanie781c812014-05-28 15:28:18 -0700466 mPm = context.getPackageManager();
Makoto Onukide3c16c2017-01-26 11:39:31 -0800467 mUserManager = context.getSystemService(UserManager.class);
Amith Yamasani4f582632014-02-19 14:31:52 -0800468 }
469
Makoto Onuki5ba0d3e2016-04-11 14:03:46 -0700470 /** @hide */
471 @TestApi
472 public LauncherApps(Context context) {
473 this(context, ILauncherApps.Stub.asInterface(
474 ServiceManager.getService(Context.LAUNCHER_APPS_SERVICE)));
475 }
476
Amith Yamasani4f582632014-02-19 14:31:52 -0800477 /**
Makoto Onukide3c16c2017-01-26 11:39:31 -0800478 * Show an error log on logcat, when the calling user is a managed profile, and the target
479 * user is different from the calling user, in order to help developers to detect it.
480 */
481 private void logErrorForInvalidProfileAccess(@NonNull UserHandle target) {
482 if (UserHandle.myUserId() != target.getIdentifier() && mUserManager.isManagedProfile()) {
Makoto Onuki3cc7cd12017-04-03 12:48:42 -0700483 Log.w(TAG, "Accessing other profiles/users from managed profile is no longer allowed.");
Makoto Onukide3c16c2017-01-26 11:39:31 -0800484 }
485 }
486
487 /**
Makoto Onukiaecbd032017-01-19 12:11:11 -0800488 * Return a list of profiles that the caller can access via the {@link LauncherApps} APIs.
489 *
490 * <p>If the caller is running on a managed profile, it'll return only the current profile.
491 * Otherwise it'll return the same list as {@link UserManager#getUserProfiles()} would.
492 */
493 public List<UserHandle> getProfiles() {
Makoto Onukide3c16c2017-01-26 11:39:31 -0800494 if (mUserManager.isManagedProfile()) {
Makoto Onukiaecbd032017-01-19 12:11:11 -0800495 // If it's a managed profile, only return the current profile.
496 final List result = new ArrayList(1);
497 result.add(android.os.Process.myUserHandle());
498 return result;
499 } else {
Makoto Onukide3c16c2017-01-26 11:39:31 -0800500 return mUserManager.getUserProfiles();
Makoto Onukiaecbd032017-01-19 12:11:11 -0800501 }
502 }
503
504 /**
Amith Yamasani4f582632014-02-19 14:31:52 -0800505 * Retrieves a list of launchable activities that match {@link Intent#ACTION_MAIN} and
Ricky Wai905908f2019-01-29 15:19:52 +0000506 * {@link Intent#CATEGORY_LAUNCHER}, for a specified user. Result may include
507 * synthesized activities like app details Activity injected by system.
Amith Yamasani4f582632014-02-19 14:31:52 -0800508 *
509 * @param packageName The specific package to query. If null, it checks all installed packages
510 * in the profile.
511 * @param user The UserHandle of the profile.
512 * @return List of launchable activities. Can be an empty list but will not be null.
513 */
514 public List<LauncherActivityInfo> getActivityList(String packageName, UserHandle user) {
Makoto Onukide3c16c2017-01-26 11:39:31 -0800515 logErrorForInvalidProfileAccess(user);
Amith Yamasani4f582632014-02-19 14:31:52 -0800516 try {
Makoto Onuki3a2541e2017-01-24 09:00:15 -0800517 return convertToActivityList(mService.getLauncherActivities(mContext.getPackageName(),
518 packageName, user), user);
Amith Yamasani4f582632014-02-19 14:31:52 -0800519 } catch (RemoteException re) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700520 throw re.rethrowFromSystemServer();
Amith Yamasani4f582632014-02-19 14:31:52 -0800521 }
Amith Yamasani4f582632014-02-19 14:31:52 -0800522 }
523
Amith Yamasani4f582632014-02-19 14:31:52 -0800524 /**
525 * Returns the activity info for a given intent and user handle, if it resolves. Otherwise it
526 * returns null.
527 *
528 * @param intent The intent to find a match for.
529 * @param user The profile to look in for a match.
530 * @return An activity info object if there is a match.
531 */
532 public LauncherActivityInfo resolveActivity(Intent intent, UserHandle user) {
Makoto Onukide3c16c2017-01-26 11:39:31 -0800533 logErrorForInvalidProfileAccess(user);
Amith Yamasani4f582632014-02-19 14:31:52 -0800534 try {
Makoto Onuki3a2541e2017-01-24 09:00:15 -0800535 ActivityInfo ai = mService.resolveActivity(mContext.getPackageName(),
536 intent.getComponent(), user);
Sunny Goyal45d3e972016-03-31 12:38:17 -0700537 if (ai != null) {
538 LauncherActivityInfo info = new LauncherActivityInfo(mContext, ai, user);
Amith Yamasani4f582632014-02-19 14:31:52 -0800539 return info;
540 }
541 } catch (RemoteException re) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700542 throw re.rethrowFromSystemServer();
Amith Yamasani4f582632014-02-19 14:31:52 -0800543 }
544 return null;
545 }
546
547 /**
Kenny Guyf939dba2014-08-15 15:32:34 +0100548 * Starts a Main activity in the specified profile.
Amith Yamasani4f582632014-02-19 14:31:52 -0800549 *
550 * @param component The ComponentName of the activity to launch
Amith Yamasanie781c812014-05-28 15:28:18 -0700551 * @param user The UserHandle of the profile
552 * @param sourceBounds The Rect containing the source bounds of the clicked icon
553 * @param opts Options to pass to startActivity
554 */
Kenny Guyf939dba2014-08-15 15:32:34 +0100555 public void startMainActivity(ComponentName component, UserHandle user, Rect sourceBounds,
Amith Yamasanie781c812014-05-28 15:28:18 -0700556 Bundle opts) {
Makoto Onukide3c16c2017-01-26 11:39:31 -0800557 logErrorForInvalidProfileAccess(user);
Amith Yamasani5abdbb62014-04-08 17:23:46 -0700558 if (DEBUG) {
Kenny Guyf939dba2014-08-15 15:32:34 +0100559 Log.i(TAG, "StartMainActivity " + component + " " + user.getIdentifier());
Amith Yamasani5abdbb62014-04-08 17:23:46 -0700560 }
Amith Yamasani4f582632014-02-19 14:31:52 -0800561 try {
Makoto Onuki1a342742018-04-26 14:56:59 -0700562 mService.startActivityAsUser(mContext.getIApplicationThread(),
563 mContext.getPackageName(),
Makoto Onuki3a2541e2017-01-24 09:00:15 -0800564 component, sourceBounds, opts, user);
Amith Yamasani4f582632014-02-19 14:31:52 -0800565 } catch (RemoteException re) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700566 throw re.rethrowFromSystemServer();
Amith Yamasani4f582632014-02-19 14:31:52 -0800567 }
568 }
569
570 /**
Jon Miranda2b340a22019-01-25 14:03:49 -0800571 * Starts an activity to show the details of the specified session.
572 *
573 * @param sessionInfo The SessionInfo of the session
574 * @param sourceBounds The Rect containing the source bounds of the clicked icon
575 * @param opts Options to pass to startActivity
576 */
Jon Miranda93505982019-03-08 09:33:42 -0800577 public void startPackageInstallerSessionDetailsActivity(@NonNull SessionInfo sessionInfo,
578 @Nullable Rect sourceBounds, @Nullable Bundle opts) {
Jon Miranda2b340a22019-01-25 14:03:49 -0800579 try {
580 mService.startSessionDetailsActivityAsUser(mContext.getIApplicationThread(),
581 mContext.getPackageName(), sessionInfo, sourceBounds, opts,
582 sessionInfo.getUser());
583 } catch (RemoteException re) {
584 throw re.rethrowFromSystemServer();
585 }
586 }
587
588 /**
Kenny Guy466d2032014-07-23 12:23:35 +0100589 * Starts the settings activity to show the application details for a
590 * package in the specified profile.
591 *
592 * @param component The ComponentName of the package to launch settings for.
593 * @param user The UserHandle of the profile
594 * @param sourceBounds The Rect containing the source bounds of the clicked icon
595 * @param opts Options to pass to startActivity
596 */
Kenny Guyf939dba2014-08-15 15:32:34 +0100597 public void startAppDetailsActivity(ComponentName component, UserHandle user,
Kenny Guy466d2032014-07-23 12:23:35 +0100598 Rect sourceBounds, Bundle opts) {
Makoto Onukide3c16c2017-01-26 11:39:31 -0800599 logErrorForInvalidProfileAccess(user);
Kenny Guy466d2032014-07-23 12:23:35 +0100600 try {
Makoto Onuki1a342742018-04-26 14:56:59 -0700601 mService.showAppDetailsAsUser(mContext.getIApplicationThread(),
602 mContext.getPackageName(),
Makoto Onuki3a2541e2017-01-24 09:00:15 -0800603 component, sourceBounds, opts, user);
Kenny Guy466d2032014-07-23 12:23:35 +0100604 } catch (RemoteException re) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700605 throw re.rethrowFromSystemServer();
Kenny Guy466d2032014-07-23 12:23:35 +0100606 }
607 }
608
609 /**
Sunny Goyala6be88a2017-01-12 16:27:58 -0800610 * Retrieves a list of config activities for creating {@link ShortcutInfo}.
611 *
612 * @param packageName The specific package to query. If null, it checks all installed packages
613 * in the profile.
614 * @param user The UserHandle of the profile.
615 * @return List of config activities. Can be an empty list but will not be null.
616 *
617 * @see Intent#ACTION_CREATE_SHORTCUT
618 * @see #getShortcutConfigActivityIntent(LauncherActivityInfo)
619 */
620 public List<LauncherActivityInfo> getShortcutConfigActivityList(@Nullable String packageName,
621 @NonNull UserHandle user) {
Makoto Onukide3c16c2017-01-26 11:39:31 -0800622 logErrorForInvalidProfileAccess(user);
Sunny Goyala6be88a2017-01-12 16:27:58 -0800623 try {
Makoto Onuki3a2541e2017-01-24 09:00:15 -0800624 return convertToActivityList(mService.getShortcutConfigActivities(
625 mContext.getPackageName(), packageName, user),
Sunny Goyala6be88a2017-01-12 16:27:58 -0800626 user);
627 } catch (RemoteException re) {
628 throw re.rethrowFromSystemServer();
629 }
630 }
631
632 private List<LauncherActivityInfo> convertToActivityList(
633 @Nullable ParceledListSlice<ResolveInfo> activities, UserHandle user) {
634 if (activities == null) {
635 return Collections.EMPTY_LIST;
636 }
637 ArrayList<LauncherActivityInfo> lais = new ArrayList<>();
638 for (ResolveInfo ri : activities.getList()) {
639 LauncherActivityInfo lai = new LauncherActivityInfo(mContext, ri.activityInfo, user);
640 if (DEBUG) {
641 Log.v(TAG, "Returning activity for profile " + user + " : "
642 + lai.getComponentName());
643 }
644 lais.add(lai);
645 }
646 return lais;
647 }
648
649 /**
650 * Returns an intent sender which can be used to start the configure activity for creating
651 * custom shortcuts. Use this method if the provider is in another profile as you are not
652 * allowed to start an activity in another profile.
653 *
654 * <p>The caller should receive {@link PinItemRequest} in onActivityResult on
655 * {@link android.app.Activity#RESULT_OK}.
656 *
657 * <p>Callers must be allowed to access the shortcut information, as defined in {@link
658 * #hasShortcutHostPermission()}.
659 *
660 * @param info a configuration activity returned by {@link #getShortcutConfigActivityList}
661 *
662 * @throws IllegalStateException when the user is locked or not running.
663 * @throws SecurityException if {@link #hasShortcutHostPermission()} is false.
664 *
665 * @see #getPinItemRequest(Intent)
666 * @see Intent#ACTION_CREATE_SHORTCUT
667 * @see android.app.Activity#startIntentSenderForResult
668 */
Makoto Onukide3c16c2017-01-26 11:39:31 -0800669 @Nullable
Sunny Goyala6be88a2017-01-12 16:27:58 -0800670 public IntentSender getShortcutConfigActivityIntent(@NonNull LauncherActivityInfo info) {
671 try {
672 return mService.getShortcutConfigActivityIntent(
673 mContext.getPackageName(), info.getComponentName(), info.getUser());
674 } catch (RemoteException re) {
675 throw re.rethrowFromSystemServer();
676 }
677 }
678
679 /**
Kenny Guy53fa4ec2014-04-29 14:24:18 +0100680 * Checks if the package is installed and enabled for a profile.
681 *
682 * @param packageName The package to check.
683 * @param user The UserHandle of the profile.
684 *
685 * @return true if the package exists and is enabled.
686 */
Kenny Guyf939dba2014-08-15 15:32:34 +0100687 public boolean isPackageEnabled(String packageName, UserHandle user) {
Makoto Onukide3c16c2017-01-26 11:39:31 -0800688 logErrorForInvalidProfileAccess(user);
Kenny Guy53fa4ec2014-04-29 14:24:18 +0100689 try {
Makoto Onuki3a2541e2017-01-24 09:00:15 -0800690 return mService.isPackageEnabled(mContext.getPackageName(), packageName, user);
Kenny Guy53fa4ec2014-04-29 14:24:18 +0100691 } catch (RemoteException re) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700692 throw re.rethrowFromSystemServer();
Kenny Guy53fa4ec2014-04-29 14:24:18 +0100693 }
694 }
695
696 /**
Suprabh Shukla19b41f32018-03-26 22:35:13 -0700697 * Gets the launcher extras supplied to the system when the given package was suspended via
698 * {@code PackageManager#setPackagesSuspended(String[], boolean, PersistableBundle,
699 * PersistableBundle, String)}.
700 *
Suprabh Shukla96212bc2018-04-10 15:04:51 -0700701 * <p>The contents of this {@link Bundle} are supposed to be a contract between the suspending
702 * app and the launcher.
703 *
Suprabh Shukla19b41f32018-03-26 22:35:13 -0700704 * <p>Note: This just returns whatever extras were provided to the system, <em>which might
705 * even be {@code null}.</em>
706 *
707 * @param packageName The package for which to fetch the launcher extras.
708 * @param user The {@link UserHandle} of the profile.
709 * @return A {@link Bundle} of launcher extras. Or {@code null} if the package is not currently
710 * suspended.
711 *
Suprabh Shukla96212bc2018-04-10 15:04:51 -0700712 * @see Callback#onPackagesSuspended(String[], UserHandle, Bundle)
Suprabh Shukla19b41f32018-03-26 22:35:13 -0700713 * @see PackageManager#isPackageSuspended()
714 */
715 public @Nullable Bundle getSuspendedPackageLauncherExtras(String packageName, UserHandle user) {
716 logErrorForInvalidProfileAccess(user);
717 try {
718 return mService.getSuspendedPackageLauncherExtras(packageName, user);
719 } catch (RemoteException re) {
720 throw re.rethrowFromSystemServer();
721 }
722 }
723
724 /**
Suprabh Shukla79000492018-12-24 17:03:02 -0800725 * Returns whether a package should be hidden from suggestions to the user. Currently, this
726 * could be done because the package was marked as distracting to the user via
727 * {@code PackageManager.setDistractingPackageRestrictions(String[], int)}.
728 *
729 * @param packageName The package for which to check.
730 * @param user the {@link UserHandle} of the profile.
731 * @return
732 */
733 public boolean shouldHideFromSuggestions(@NonNull String packageName,
734 @NonNull UserHandle user) {
735 Preconditions.checkNotNull(packageName, "packageName");
736 Preconditions.checkNotNull(user, "user");
737 try {
738 return mService.shouldHideFromSuggestions(packageName, user);
739 } catch (RemoteException re) {
740 throw re.rethrowFromSystemServer();
741 }
742 }
743
744 /**
Benjamin Miller7afa84c2017-07-17 13:01:35 +0200745 * Returns {@link ApplicationInfo} about an application installed for a specific user profile.
Kenny Guy77242752016-01-15 13:29:06 +0000746 *
Amith Yamasani0d1fd8d2016-10-12 14:21:51 -0700747 * @param packageName The package name of the application
Kenny Guy77242752016-01-15 13:29:06 +0000748 * @param flags Additional option flags {@link PackageManager#getApplicationInfo}
749 * @param user The UserHandle of the profile.
750 *
Benjamin Miller7afa84c2017-07-17 13:01:35 +0200751 * @return {@link ApplicationInfo} containing information about the package. Returns
752 * {@code null} if the package isn't installed for the given profile, or the profile
753 * isn't enabled.
Kenny Guy77242752016-01-15 13:29:06 +0000754 */
Makoto Onuki7c7fbf62017-04-14 11:03:56 -0700755 public ApplicationInfo getApplicationInfo(@NonNull String packageName,
756 @ApplicationInfoFlags int flags, @NonNull UserHandle user)
757 throws PackageManager.NameNotFoundException {
758 Preconditions.checkNotNull(packageName, "packageName");
Suprabh Shukla19b41f32018-03-26 22:35:13 -0700759 Preconditions.checkNotNull(user, "user");
Makoto Onukide3c16c2017-01-26 11:39:31 -0800760 logErrorForInvalidProfileAccess(user);
Kenny Guy77242752016-01-15 13:29:06 +0000761 try {
Makoto Onuki7c7fbf62017-04-14 11:03:56 -0700762 final ApplicationInfo ai = mService
763 .getApplicationInfo(mContext.getPackageName(), packageName, flags, user);
764 if (ai == null) {
765 throw new NameNotFoundException("Package " + packageName + " not found for user "
766 + user.getIdentifier());
767 }
768 return ai;
Kenny Guy77242752016-01-15 13:29:06 +0000769 } catch (RemoteException re) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700770 throw re.rethrowFromSystemServer();
Kenny Guy77242752016-01-15 13:29:06 +0000771 }
772 }
773
774 /**
Varun Shah2546cef2019-01-11 15:50:54 -0800775 * Returns an object describing the app usage limit for the given package.
776 * If there are multiple limits that apply to the package, the one with the smallest
777 * time remaining will be returned.
778 *
779 * @param packageName name of the package whose app usage limit will be returned
780 * @param user the user of the package
781 *
782 * @return an {@link AppUsageLimit} object describing the app time limit containing
783 * the given package with the smallest time remaining, or {@code null} if none exist.
Varun Shahe9abb752019-02-11 11:25:06 -0800784 * @throws SecurityException when the caller is not the recents app.
Varun Shah2546cef2019-01-11 15:50:54 -0800785 */
786 @Nullable
Varun Shah2c9263c2019-02-15 10:51:10 -0800787 public LauncherApps.AppUsageLimit getAppUsageLimit(@NonNull String packageName,
788 @NonNull UserHandle user) {
Varun Shah2546cef2019-01-11 15:50:54 -0800789 try {
790 return mService.getAppUsageLimit(mContext.getPackageName(), packageName, user);
791 } catch (RemoteException re) {
792 throw re.rethrowFromSystemServer();
793 }
794 }
795
796 /**
Kenny Guy53fa4ec2014-04-29 14:24:18 +0100797 * Checks if the activity exists and it enabled for a profile.
798 *
Makoto Onuki516020a2019-01-28 14:16:42 -0800799 * <p>The activity may still not be exported, in which case {@link #startMainActivity} will
800 * throw a {@link SecurityException} unless the caller has the same UID as the target app's.
801 *
Kenny Guy53fa4ec2014-04-29 14:24:18 +0100802 * @param component The activity to check.
803 * @param user The UserHandle of the profile.
804 *
805 * @return true if the activity exists and is enabled.
806 */
Kenny Guyf939dba2014-08-15 15:32:34 +0100807 public boolean isActivityEnabled(ComponentName component, UserHandle user) {
Makoto Onukide3c16c2017-01-26 11:39:31 -0800808 logErrorForInvalidProfileAccess(user);
Kenny Guy53fa4ec2014-04-29 14:24:18 +0100809 try {
Makoto Onuki3a2541e2017-01-24 09:00:15 -0800810 return mService.isActivityEnabled(mContext.getPackageName(), component, user);
Kenny Guy53fa4ec2014-04-29 14:24:18 +0100811 } catch (RemoteException re) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700812 throw re.rethrowFromSystemServer();
Kenny Guy53fa4ec2014-04-29 14:24:18 +0100813 }
814 }
815
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800816 /**
Dianne Hackbornc160fa42017-11-01 16:14:26 -0700817 * Returns whether the caller can access the shortcut information. Access is currently
818 * available to:
Makoto Onuki2d5b4652016-03-11 16:09:54 -0800819 *
Dianne Hackbornc160fa42017-11-01 16:14:26 -0700820 * <ul>
821 * <li>The current launcher (or default launcher if there is no set current launcher).</li>
822 * <li>The currently active voice interaction service.</li>
823 * </ul>
Makoto Onuki2d5b4652016-03-11 16:09:54 -0800824 *
Makoto Onuki4a910962016-07-07 13:57:34 -0700825 * <p>Note when this method returns {@code false}, it may be a temporary situation because
Makoto Onuki2d5b4652016-03-11 16:09:54 -0800826 * the user is trying a new launcher application. The user may decide to change the default
Makoto Onuki4a910962016-07-07 13:57:34 -0700827 * launcher back to the calling application again, so even if a launcher application loses
Makoto Onuki2d5b4652016-03-11 16:09:54 -0800828 * this permission, it does <b>not</b> have to purge pinned shortcut information.
Makoto Onukife9c9662016-07-25 15:12:23 -0700829 * If the calling launcher application contains pinned shortcuts, they will still work,
830 * even though the caller no longer has the shortcut host permission.
Makoto Onuki4a910962016-07-07 13:57:34 -0700831 *
Makoto Onuki02f338e2016-07-29 09:40:40 -0700832 * @throws IllegalStateException when the user is locked.
Makoto Onuki9c850012016-07-26 15:50:50 -0700833 *
Makoto Onuki4a910962016-07-07 13:57:34 -0700834 * @see ShortcutManager
Makoto Onuki2d5b4652016-03-11 16:09:54 -0800835 */
836 public boolean hasShortcutHostPermission() {
837 try {
838 return mService.hasShortcutHostPermission(mContext.getPackageName());
839 } catch (RemoteException re) {
840 throw re.rethrowFromSystemServer();
841 }
842 }
843
Makoto Onukib1588c02017-10-12 15:11:45 -0700844 private List<ShortcutInfo> maybeUpdateDisabledMessage(List<ShortcutInfo> shortcuts) {
845 if (shortcuts == null) {
846 return null;
847 }
848 for (int i = shortcuts.size() - 1; i >= 0; i--) {
849 final ShortcutInfo si = shortcuts.get(i);
850 final String message = ShortcutInfo.getDisabledReasonForRestoreIssue(mContext,
851 si.getDisabledReason());
852 if (message != null) {
853 si.setDisabledMessage(message);
854 }
855 }
856 return shortcuts;
857 }
858
Makoto Onuki2d5b4652016-03-11 16:09:54 -0800859 /**
Makoto Onuki4a910962016-07-07 13:57:34 -0700860 * Returns {@link ShortcutInfo}s that match {@code query}.
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800861 *
Makoto Onuki2d5b4652016-03-11 16:09:54 -0800862 * <p>Callers must be allowed to access the shortcut information, as defined in {@link
863 * #hasShortcutHostPermission()}.
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800864 *
865 * @param query result includes shortcuts matching this query.
866 * @param user The UserHandle of the profile.
867 *
868 * @return the IDs of {@link ShortcutInfo}s that match the query.
Makoto Onuki02f338e2016-07-29 09:40:40 -0700869 * @throws IllegalStateException when the user is locked, or when the {@code user} user
870 * is locked or not running.
Makoto Onuki4a910962016-07-07 13:57:34 -0700871 *
872 * @see ShortcutManager
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800873 */
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800874 @Nullable
875 public List<ShortcutInfo> getShortcuts(@NonNull ShortcutQuery query,
876 @NonNull UserHandle user) {
Makoto Onukide3c16c2017-01-26 11:39:31 -0800877 logErrorForInvalidProfileAccess(user);
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800878 try {
Makoto Onukib1588c02017-10-12 15:11:45 -0700879 // Note this is the only case we need to update the disabled message for shortcuts
880 // that weren't restored.
881 // The restore problem messages are only shown by the user, and publishers will never
882 // see them. The only other API that the launcher gets shortcuts is the shortcut
883 // changed callback, but that only returns shortcuts with the "key" information, so
884 // that won't return disabled message.
885 return maybeUpdateDisabledMessage(mService.getShortcuts(mContext.getPackageName(),
Makoto Onukiabe84422016-04-07 09:41:19 -0700886 query.mChangedSince, query.mPackage, query.mShortcutIds, query.mActivity,
Makoto Onuki99302b52017-03-29 12:42:26 -0700887 query.mQueryFlags, user)
Makoto Onukib1588c02017-10-12 15:11:45 -0700888 .getList());
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800889 } catch (RemoteException e) {
890 throw e.rethrowFromSystemServer();
891 }
892 }
893
894 /**
Makoto Onukiabe84422016-04-07 09:41:19 -0700895 * @hide // No longer used. Use getShortcuts() instead. Kept for unit tests.
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800896 */
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800897 @Nullable
Makoto Onukib5a012f2016-06-21 11:13:53 -0700898 @Deprecated
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800899 public List<ShortcutInfo> getShortcutInfo(@NonNull String packageName,
900 @NonNull List<String> ids, @NonNull UserHandle user) {
Makoto Onukiabe84422016-04-07 09:41:19 -0700901 final ShortcutQuery q = new ShortcutQuery();
902 q.setPackage(packageName);
903 q.setShortcutIds(ids);
Makoto Onuki4d6b87f2016-06-17 13:47:40 -0700904 q.setQueryFlags(ShortcutQuery.FLAG_GET_ALL_KINDS);
Makoto Onukiabe84422016-04-07 09:41:19 -0700905 return getShortcuts(q, user);
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800906 }
907
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800908 /**
909 * Pin shortcuts on a package.
910 *
911 * <p>This API is <b>NOT</b> cumulative; this will replace all pinned shortcuts for the package.
912 * However, different launchers may have different set of pinned shortcuts.
913 *
Makoto Onukife9c9662016-07-25 15:12:23 -0700914 * <p>The calling launcher application must be allowed to access the shortcut information,
915 * as defined in {@link #hasShortcutHostPermission()}.
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800916 *
917 * @param packageName The target package name.
918 * @param shortcutIds The IDs of the shortcut to be pinned.
919 * @param user The UserHandle of the profile.
Makoto Onuki02f338e2016-07-29 09:40:40 -0700920 * @throws IllegalStateException when the user is locked, or when the {@code user} user
921 * is locked or not running.
Makoto Onuki4a910962016-07-07 13:57:34 -0700922 *
923 * @see ShortcutManager
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800924 */
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800925 public void pinShortcuts(@NonNull String packageName, @NonNull List<String> shortcutIds,
926 @NonNull UserHandle user) {
Makoto Onukide3c16c2017-01-26 11:39:31 -0800927 logErrorForInvalidProfileAccess(user);
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800928 try {
929 mService.pinShortcuts(mContext.getPackageName(), packageName, shortcutIds, user);
930 } catch (RemoteException e) {
931 throw e.rethrowFromSystemServer();
932 }
933 }
934
935 /**
Makoto Onukib6d35232016-04-04 15:57:17 -0700936 * @hide kept for testing.
Makoto Onukiabe84422016-04-07 09:41:19 -0700937 */
Makoto Onukib5a012f2016-06-21 11:13:53 -0700938 @Deprecated
Makoto Onukiabe84422016-04-07 09:41:19 -0700939 public int getShortcutIconResId(@NonNull ShortcutInfo shortcut) {
Makoto Onukib6d35232016-04-04 15:57:17 -0700940 return shortcut.getIconResourceId();
Makoto Onukiabe84422016-04-07 09:41:19 -0700941 }
942
943 /**
Makoto Onukib6d35232016-04-04 15:57:17 -0700944 * @hide kept for testing.
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800945 */
Makoto Onukib5a012f2016-06-21 11:13:53 -0700946 @Deprecated
Makoto Onukiabe84422016-04-07 09:41:19 -0700947 public int getShortcutIconResId(@NonNull String packageName, @NonNull String shortcutId,
948 @NonNull UserHandle user) {
Makoto Onukib6d35232016-04-04 15:57:17 -0700949 final ShortcutQuery q = new ShortcutQuery();
950 q.setPackage(packageName);
951 q.setShortcutIds(Arrays.asList(shortcutId));
Makoto Onuki4d6b87f2016-06-17 13:47:40 -0700952 q.setQueryFlags(ShortcutQuery.FLAG_GET_ALL_KINDS);
Makoto Onukib6d35232016-04-04 15:57:17 -0700953 final List<ShortcutInfo> shortcuts = getShortcuts(q, user);
Makoto Onukiabe84422016-04-07 09:41:19 -0700954
Makoto Onukib6d35232016-04-04 15:57:17 -0700955 return shortcuts.size() > 0 ? shortcuts.get(0).getIconResourceId() : 0;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800956 }
957
958 /**
Makoto Onukib5a012f2016-06-21 11:13:53 -0700959 * @hide internal/unit tests only
Makoto Onukiabe84422016-04-07 09:41:19 -0700960 */
961 public ParcelFileDescriptor getShortcutIconFd(
962 @NonNull ShortcutInfo shortcut) {
Makoto Onuki22fcc682016-05-17 14:52:19 -0700963 return getShortcutIconFd(shortcut.getPackage(), shortcut.getId(),
Makoto Onukiabe84422016-04-07 09:41:19 -0700964 shortcut.getUserId());
965 }
966
967 /**
Makoto Onukib5a012f2016-06-21 11:13:53 -0700968 * @hide internal/unit tests only
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800969 */
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800970 public ParcelFileDescriptor getShortcutIconFd(
Makoto Onukiabe84422016-04-07 09:41:19 -0700971 @NonNull String packageName, @NonNull String shortcutId, @NonNull UserHandle user) {
972 return getShortcutIconFd(packageName, shortcutId, user.getIdentifier());
973 }
974
975 private ParcelFileDescriptor getShortcutIconFd(
976 @NonNull String packageName, @NonNull String shortcutId, int userId) {
Makoto Onuki55046222016-03-08 10:49:47 -0800977 try {
Makoto Onukiabe84422016-04-07 09:41:19 -0700978 return mService.getShortcutIconFd(mContext.getPackageName(),
979 packageName, shortcutId, userId);
Makoto Onuki55046222016-03-08 10:49:47 -0800980 } catch (RemoteException e) {
981 throw e.rethrowFromSystemServer();
982 }
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800983 }
984
Makoto Onuki04b9aab2016-05-23 17:13:30 -0700985 /**
986 * Returns the icon for this shortcut, without any badging for the profile.
987 *
Makoto Onukife9c9662016-07-25 15:12:23 -0700988 * <p>The calling launcher application must be allowed to access the shortcut information,
989 * as defined in {@link #hasShortcutHostPermission()}.
Makoto Onuki4a910962016-07-07 13:57:34 -0700990 *
Makoto Onuki04b9aab2016-05-23 17:13:30 -0700991 * @param density The preferred density of the icon, zero for default density. Use
992 * density DPI values from {@link DisplayMetrics}.
Makoto Onuki4a910962016-07-07 13:57:34 -0700993 *
994 * @return The drawable associated with the shortcut.
Makoto Onuki02f338e2016-07-29 09:40:40 -0700995 * @throws IllegalStateException when the user is locked, or when the {@code user} user
996 * is locked or not running.
Makoto Onuki4a910962016-07-07 13:57:34 -0700997 *
998 * @see ShortcutManager
Makoto Onuki04b9aab2016-05-23 17:13:30 -0700999 * @see #getShortcutBadgedIconDrawable(ShortcutInfo, int)
1000 * @see DisplayMetrics
Makoto Onuki04b9aab2016-05-23 17:13:30 -07001001 */
1002 public Drawable getShortcutIconDrawable(@NonNull ShortcutInfo shortcut, int density) {
1003 if (shortcut.hasIconFile()) {
1004 final ParcelFileDescriptor pfd = getShortcutIconFd(shortcut);
1005 if (pfd == null) {
1006 return null;
1007 }
1008 try {
1009 final Bitmap bmp = BitmapFactory.decodeFileDescriptor(pfd.getFileDescriptor());
Hyunyoung Songf281e7a2017-02-13 10:57:42 -08001010 if (bmp != null) {
1011 BitmapDrawable dr = new BitmapDrawable(mContext.getResources(), bmp);
Hyunyoung Songe4179e22017-03-01 12:51:26 -08001012 if (shortcut.hasAdaptiveBitmap()) {
Hyunyoung Songbe8835e2017-02-17 11:25:08 -08001013 return new AdaptiveIconDrawable(null, dr);
Hyunyoung Songf281e7a2017-02-13 10:57:42 -08001014 } else {
1015 return dr;
1016 }
1017 }
1018 return null;
Makoto Onuki04b9aab2016-05-23 17:13:30 -07001019 } finally {
1020 try {
1021 pfd.close();
1022 } catch (IOException ignore) {
1023 }
1024 }
1025 } else if (shortcut.hasIconResource()) {
Makoto Onuki2d895c32016-12-02 15:48:40 -08001026 return loadDrawableResourceFromPackage(shortcut.getPackage(),
1027 shortcut.getIconResourceId(), shortcut.getUserHandle(), density);
1028 } else if (shortcut.getIcon() != null) {
1029 // This happens if a shortcut is pending-approval.
1030 final Icon icon = shortcut.getIcon();
1031 switch (icon.getType()) {
1032 case Icon.TYPE_RESOURCE: {
1033 return loadDrawableResourceFromPackage(shortcut.getPackage(),
1034 icon.getResId(), shortcut.getUserHandle(), density);
Makoto Onuki04b9aab2016-05-23 17:13:30 -07001035 }
Hyunyoung Songf281e7a2017-02-13 10:57:42 -08001036 case Icon.TYPE_BITMAP:
Hyunyoung Songe4179e22017-03-01 12:51:26 -08001037 case Icon.TYPE_ADAPTIVE_BITMAP: {
Makoto Onuki2d895c32016-12-02 15:48:40 -08001038 return icon.loadDrawable(mContext);
1039 }
1040 default:
1041 return null; // Shouldn't happen though.
Makoto Onuki04b9aab2016-05-23 17:13:30 -07001042 }
1043 } else {
1044 return null; // Has no icon.
1045 }
Makoto Onuki20c95f82016-05-11 16:51:01 -07001046 }
1047
Makoto Onuki2d895c32016-12-02 15:48:40 -08001048 private Drawable loadDrawableResourceFromPackage(String packageName, int resId,
1049 UserHandle user, int density) {
1050 try {
1051 if (resId == 0) {
1052 return null; // Shouldn't happen but just in case.
1053 }
1054 final ApplicationInfo ai = getApplicationInfo(packageName, /* flags =*/ 0, user);
1055 final Resources res = mContext.getPackageManager().getResourcesForApplication(ai);
1056 return res.getDrawableForDensity(resId, density);
1057 } catch (NameNotFoundException | Resources.NotFoundException e) {
1058 return null;
1059 }
1060 }
1061
Makoto Onuki04b9aab2016-05-23 17:13:30 -07001062 /**
1063 * Returns the shortcut icon with badging appropriate for the profile.
1064 *
Makoto Onukife9c9662016-07-25 15:12:23 -07001065 * <p>The calling launcher application must be allowed to access the shortcut information,
1066 * as defined in {@link #hasShortcutHostPermission()}.
Makoto Onuki4a910962016-07-07 13:57:34 -07001067 *
Makoto Onuki04b9aab2016-05-23 17:13:30 -07001068 * @param density Optional density for the icon, or 0 to use the default density. Use
Makoto Onuki04b9aab2016-05-23 17:13:30 -07001069 * @return A badged icon for the shortcut.
Makoto Onuki02f338e2016-07-29 09:40:40 -07001070 * @throws IllegalStateException when the user is locked, or when the {@code user} user
1071 * is locked or not running.
Makoto Onuki4a910962016-07-07 13:57:34 -07001072 *
1073 * @see ShortcutManager
Makoto Onukife9c9662016-07-25 15:12:23 -07001074 * @see #getShortcutIconDrawable(ShortcutInfo, int)
Makoto Onuki4a910962016-07-07 13:57:34 -07001075 * @see DisplayMetrics
Makoto Onuki04b9aab2016-05-23 17:13:30 -07001076 */
1077 public Drawable getShortcutBadgedIconDrawable(ShortcutInfo shortcut, int density) {
1078 final Drawable originalIcon = getShortcutIconDrawable(shortcut, density);
1079
1080 return (originalIcon == null) ? null : mContext.getPackageManager().getUserBadgedIcon(
1081 originalIcon, shortcut.getUserHandle());
Makoto Onuki20c95f82016-05-11 16:51:01 -07001082 }
1083
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001084 /**
Makoto Onuki4a910962016-07-07 13:57:34 -07001085 * Starts a shortcut.
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001086 *
Makoto Onukife9c9662016-07-25 15:12:23 -07001087 * <p>The calling launcher application must be allowed to access the shortcut information,
1088 * as defined in {@link #hasShortcutHostPermission()}.
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001089 *
Makoto Onuki43204b82016-03-08 16:16:44 -08001090 * @param packageName The target shortcut package name.
1091 * @param shortcutId The target shortcut ID.
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001092 * @param sourceBounds The Rect containing the source bounds of the clicked icon.
1093 * @param startActivityOptions Options to pass to startActivity.
1094 * @param user The UserHandle of the profile.
Makoto Onuki02f338e2016-07-29 09:40:40 -07001095 * @throws IllegalStateException when the user is locked, or when the {@code user} user
1096 * is locked or not running.
Makoto Onuki83f6d2d2016-07-11 14:30:19 -07001097 *
1098 * @throws android.content.ActivityNotFoundException failed to start shortcut. (e.g.
1099 * the shortcut no longer exists, is disabled, the intent receiver activity doesn't exist, etc)
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001100 */
Makoto Onukid6880792016-06-29 13:37:43 -07001101 public void startShortcut(@NonNull String packageName, @NonNull String shortcutId,
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001102 @Nullable Rect sourceBounds, @Nullable Bundle startActivityOptions,
1103 @NonNull UserHandle user) {
Makoto Onukide3c16c2017-01-26 11:39:31 -08001104 logErrorForInvalidProfileAccess(user);
1105
Makoto Onukid6880792016-06-29 13:37:43 -07001106 startShortcut(packageName, shortcutId, sourceBounds, startActivityOptions,
Makoto Onukiabe84422016-04-07 09:41:19 -07001107 user.getIdentifier());
1108 }
1109
1110 /**
1111 * Launches a shortcut.
1112 *
Makoto Onukife9c9662016-07-25 15:12:23 -07001113 * <p>The calling launcher application must be allowed to access the shortcut information,
1114 * as defined in {@link #hasShortcutHostPermission()}.
Makoto Onukiabe84422016-04-07 09:41:19 -07001115 *
1116 * @param shortcut The target shortcut.
1117 * @param sourceBounds The Rect containing the source bounds of the clicked icon.
1118 * @param startActivityOptions Options to pass to startActivity.
Makoto Onuki02f338e2016-07-29 09:40:40 -07001119 * @throws IllegalStateException when the user is locked, or when the {@code user} user
1120 * is locked or not running.
Makoto Onuki83f6d2d2016-07-11 14:30:19 -07001121 *
1122 * @throws android.content.ActivityNotFoundException failed to start shortcut. (e.g.
1123 * the shortcut no longer exists, is disabled, the intent receiver activity doesn't exist, etc)
Makoto Onukiabe84422016-04-07 09:41:19 -07001124 */
Makoto Onukid6880792016-06-29 13:37:43 -07001125 public void startShortcut(@NonNull ShortcutInfo shortcut,
Makoto Onukiabe84422016-04-07 09:41:19 -07001126 @Nullable Rect sourceBounds, @Nullable Bundle startActivityOptions) {
Makoto Onukid6880792016-06-29 13:37:43 -07001127 startShortcut(shortcut.getPackage(), shortcut.getId(),
Makoto Onukiabe84422016-04-07 09:41:19 -07001128 sourceBounds, startActivityOptions,
1129 shortcut.getUserId());
1130 }
1131
Mathew Inwood5c0d3542018-08-14 13:54:31 +01001132 @UnsupportedAppUsage
Makoto Onukid6880792016-06-29 13:37:43 -07001133 private void startShortcut(@NonNull String packageName, @NonNull String shortcutId,
Makoto Onukiabe84422016-04-07 09:41:19 -07001134 @Nullable Rect sourceBounds, @Nullable Bundle startActivityOptions,
1135 int userId) {
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001136 try {
Makoto Onuki83f6d2d2016-07-11 14:30:19 -07001137 final boolean success =
1138 mService.startShortcut(mContext.getPackageName(), packageName, shortcutId,
Makoto Onukiabe84422016-04-07 09:41:19 -07001139 sourceBounds, startActivityOptions, userId);
Makoto Onuki83f6d2d2016-07-11 14:30:19 -07001140 if (!success) {
1141 throw new ActivityNotFoundException("Shortcut could not be started");
1142 }
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001143 } catch (RemoteException e) {
1144 throw e.rethrowFromSystemServer();
1145 }
1146 }
Kenny Guy53fa4ec2014-04-29 14:24:18 +01001147
1148 /**
Jon Miranda2b340a22019-01-25 14:03:49 -08001149 * Registers a callback for changes to packages in this user and managed profiles.
Kenny Guyc01545372014-06-16 14:17:26 +01001150 *
Kenny Guy10a574f2014-08-26 16:17:58 +01001151 * @param callback The callback to register.
Kenny Guyc01545372014-06-16 14:17:26 +01001152 */
Kenny Guy10a574f2014-08-26 16:17:58 +01001153 public void registerCallback(Callback callback) {
1154 registerCallback(callback, null);
Kenny Guyb42c89b2014-07-28 19:20:07 +01001155 }
1156
1157 /**
Jon Miranda2b340a22019-01-25 14:03:49 -08001158 * Registers a callback for changes to packages in this user and managed profiles.
Kenny Guyb42c89b2014-07-28 19:20:07 +01001159 *
Kenny Guy10a574f2014-08-26 16:17:58 +01001160 * @param callback The callback to register.
Kenny Guyb42c89b2014-07-28 19:20:07 +01001161 * @param handler that should be used to post callbacks on, may be null.
1162 */
Kenny Guy10a574f2014-08-26 16:17:58 +01001163 public void registerCallback(Callback callback, Handler handler) {
Kenny Guyc01545372014-06-16 14:17:26 +01001164 synchronized (this) {
Kenny Guy172a2162015-06-19 17:21:28 +01001165 if (callback != null && findCallbackLocked(callback) < 0) {
Kenny Guyb42c89b2014-07-28 19:20:07 +01001166 boolean addedFirstCallback = mCallbacks.size() == 0;
1167 addCallbackLocked(callback, handler);
1168 if (addedFirstCallback) {
Kenny Guyc01545372014-06-16 14:17:26 +01001169 try {
Makoto Onuki4dbe0de2016-03-14 17:31:49 -07001170 mService.addOnAppsChangedListener(mContext.getPackageName(),
1171 mAppsChangedListener);
Kenny Guyc01545372014-06-16 14:17:26 +01001172 } catch (RemoteException re) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001173 throw re.rethrowFromSystemServer();
Kenny Guyc01545372014-06-16 14:17:26 +01001174 }
1175 }
1176 }
1177 }
1178 }
1179
1180 /**
Kenny Guy10a574f2014-08-26 16:17:58 +01001181 * Unregisters a callback that was previously registered.
Kenny Guyc01545372014-06-16 14:17:26 +01001182 *
Kenny Guy10a574f2014-08-26 16:17:58 +01001183 * @param callback The callback to unregister.
1184 * @see #registerCallback(Callback)
Kenny Guyc01545372014-06-16 14:17:26 +01001185 */
Kenny Guy10a574f2014-08-26 16:17:58 +01001186 public void unregisterCallback(Callback callback) {
Kenny Guyc01545372014-06-16 14:17:26 +01001187 synchronized (this) {
Kenny Guyb42c89b2014-07-28 19:20:07 +01001188 removeCallbackLocked(callback);
Kenny Guy44b6dee2014-07-10 18:10:14 +01001189 if (mCallbacks.size() == 0) {
Amith Yamasanie781c812014-05-28 15:28:18 -07001190 try {
1191 mService.removeOnAppsChangedListener(mAppsChangedListener);
1192 } catch (RemoteException re) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001193 throw re.rethrowFromSystemServer();
Amith Yamasanie781c812014-05-28 15:28:18 -07001194 }
Amith Yamasani4f582632014-02-19 14:31:52 -08001195 }
1196 }
1197 }
1198
Kenny Guy172a2162015-06-19 17:21:28 +01001199 /** @return position in mCallbacks for callback or -1 if not present. */
1200 private int findCallbackLocked(Callback callback) {
Kenny Guyb42c89b2014-07-28 19:20:07 +01001201 if (callback == null) {
1202 throw new IllegalArgumentException("Callback cannot be null");
1203 }
1204 final int size = mCallbacks.size();
1205 for (int i = 0; i < size; ++i) {
1206 if (mCallbacks.get(i).mCallback == callback) {
Kenny Guy172a2162015-06-19 17:21:28 +01001207 return i;
Kenny Guyb42c89b2014-07-28 19:20:07 +01001208 }
1209 }
Kenny Guy172a2162015-06-19 17:21:28 +01001210 return -1;
1211 }
1212
1213 private void removeCallbackLocked(Callback callback) {
1214 int pos = findCallbackLocked(callback);
1215 if (pos >= 0) {
1216 mCallbacks.remove(pos);
1217 }
Kenny Guyb42c89b2014-07-28 19:20:07 +01001218 }
1219
Kenny Guyf939dba2014-08-15 15:32:34 +01001220 private void addCallbackLocked(Callback callback, Handler handler) {
Kenny Guyb42c89b2014-07-28 19:20:07 +01001221 // Remove if already present.
1222 removeCallbackLocked(callback);
1223 if (handler == null) {
1224 handler = new Handler();
1225 }
1226 CallbackMessageHandler toAdd = new CallbackMessageHandler(handler.getLooper(), callback);
1227 mCallbacks.add(toAdd);
1228 }
1229
Amith Yamasani4f582632014-02-19 14:31:52 -08001230 private IOnAppsChangedListener.Stub mAppsChangedListener = new IOnAppsChangedListener.Stub() {
1231
1232 @Override
Kenny Guyb42c89b2014-07-28 19:20:07 +01001233 public void onPackageRemoved(UserHandle user, String packageName)
1234 throws RemoteException {
Amith Yamasani4f582632014-02-19 14:31:52 -08001235 if (DEBUG) {
1236 Log.d(TAG, "onPackageRemoved " + user.getIdentifier() + "," + packageName);
1237 }
1238 synchronized (LauncherApps.this) {
Kenny Guyb42c89b2014-07-28 19:20:07 +01001239 for (CallbackMessageHandler callback : mCallbacks) {
1240 callback.postOnPackageRemoved(packageName, user);
Kenny Guyc01545372014-06-16 14:17:26 +01001241 }
Amith Yamasani4f582632014-02-19 14:31:52 -08001242 }
1243 }
1244
1245 @Override
1246 public void onPackageChanged(UserHandle user, String packageName) throws RemoteException {
1247 if (DEBUG) {
1248 Log.d(TAG, "onPackageChanged " + user.getIdentifier() + "," + packageName);
1249 }
1250 synchronized (LauncherApps.this) {
Kenny Guyb42c89b2014-07-28 19:20:07 +01001251 for (CallbackMessageHandler callback : mCallbacks) {
1252 callback.postOnPackageChanged(packageName, user);
Kenny Guyc01545372014-06-16 14:17:26 +01001253 }
Amith Yamasani4f582632014-02-19 14:31:52 -08001254 }
1255 }
1256
1257 @Override
1258 public void onPackageAdded(UserHandle user, String packageName) throws RemoteException {
1259 if (DEBUG) {
1260 Log.d(TAG, "onPackageAdded " + user.getIdentifier() + "," + packageName);
1261 }
1262 synchronized (LauncherApps.this) {
Kenny Guyb42c89b2014-07-28 19:20:07 +01001263 for (CallbackMessageHandler callback : mCallbacks) {
1264 callback.postOnPackageAdded(packageName, user);
Kenny Guyc01545372014-06-16 14:17:26 +01001265 }
Amith Yamasani4f582632014-02-19 14:31:52 -08001266 }
1267 }
1268
1269 @Override
1270 public void onPackagesAvailable(UserHandle user, String[] packageNames, boolean replacing)
1271 throws RemoteException {
1272 if (DEBUG) {
1273 Log.d(TAG, "onPackagesAvailable " + user.getIdentifier() + "," + packageNames);
1274 }
1275 synchronized (LauncherApps.this) {
Kenny Guyb42c89b2014-07-28 19:20:07 +01001276 for (CallbackMessageHandler callback : mCallbacks) {
1277 callback.postOnPackagesAvailable(packageNames, user, replacing);
Kenny Guyc01545372014-06-16 14:17:26 +01001278 }
Amith Yamasani4f582632014-02-19 14:31:52 -08001279 }
1280 }
1281
1282 @Override
1283 public void onPackagesUnavailable(UserHandle user, String[] packageNames, boolean replacing)
1284 throws RemoteException {
1285 if (DEBUG) {
1286 Log.d(TAG, "onPackagesUnavailable " + user.getIdentifier() + "," + packageNames);
1287 }
1288 synchronized (LauncherApps.this) {
Kenny Guyb42c89b2014-07-28 19:20:07 +01001289 for (CallbackMessageHandler callback : mCallbacks) {
1290 callback.postOnPackagesUnavailable(packageNames, user, replacing);
Kenny Guyc01545372014-06-16 14:17:26 +01001291 }
Kenny Guy77242752016-01-15 13:29:06 +00001292 }
1293 }
1294
1295 @Override
Suprabh Shukla19b41f32018-03-26 22:35:13 -07001296 public void onPackagesSuspended(UserHandle user, String[] packageNames,
1297 Bundle launcherExtras)
Kenny Guy77242752016-01-15 13:29:06 +00001298 throws RemoteException {
1299 if (DEBUG) {
1300 Log.d(TAG, "onPackagesSuspended " + user.getIdentifier() + "," + packageNames);
1301 }
1302 synchronized (LauncherApps.this) {
1303 for (CallbackMessageHandler callback : mCallbacks) {
Suprabh Shukla19b41f32018-03-26 22:35:13 -07001304 callback.postOnPackagesSuspended(packageNames, launcherExtras, user);
Kenny Guy77242752016-01-15 13:29:06 +00001305 }
1306 }
1307 }
1308
1309 @Override
1310 public void onPackagesUnsuspended(UserHandle user, String[] packageNames)
1311 throws RemoteException {
1312 if (DEBUG) {
1313 Log.d(TAG, "onPackagesUnsuspended " + user.getIdentifier() + "," + packageNames);
1314 }
1315 synchronized (LauncherApps.this) {
1316 for (CallbackMessageHandler callback : mCallbacks) {
1317 callback.postOnPackagesUnsuspended(packageNames, user);
1318 }
1319 }
Amith Yamasani4f582632014-02-19 14:31:52 -08001320 }
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001321
1322 @Override
1323 public void onShortcutChanged(UserHandle user, String packageName,
1324 ParceledListSlice shortcuts) {
1325 if (DEBUG) {
1326 Log.d(TAG, "onShortcutChanged " + user.getIdentifier() + "," + packageName);
1327 }
1328 final List<ShortcutInfo> list = shortcuts.getList();
1329 synchronized (LauncherApps.this) {
1330 for (CallbackMessageHandler callback : mCallbacks) {
1331 callback.postOnShortcutChanged(packageName, user, list);
1332 }
1333 }
1334 }
Amith Yamasani4f582632014-02-19 14:31:52 -08001335 };
Kenny Guyb42c89b2014-07-28 19:20:07 +01001336
1337 private static class CallbackMessageHandler extends Handler {
1338 private static final int MSG_ADDED = 1;
1339 private static final int MSG_REMOVED = 2;
1340 private static final int MSG_CHANGED = 3;
1341 private static final int MSG_AVAILABLE = 4;
1342 private static final int MSG_UNAVAILABLE = 5;
Kenny Guy77242752016-01-15 13:29:06 +00001343 private static final int MSG_SUSPENDED = 6;
1344 private static final int MSG_UNSUSPENDED = 7;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001345 private static final int MSG_SHORTCUT_CHANGED = 8;
Kenny Guyb42c89b2014-07-28 19:20:07 +01001346
Kenny Guyf939dba2014-08-15 15:32:34 +01001347 private LauncherApps.Callback mCallback;
Kenny Guyb42c89b2014-07-28 19:20:07 +01001348
1349 private static class CallbackInfo {
1350 String[] packageNames;
1351 String packageName;
Suprabh Shukla19b41f32018-03-26 22:35:13 -07001352 Bundle launcherExtras;
Kenny Guyb42c89b2014-07-28 19:20:07 +01001353 boolean replacing;
1354 UserHandle user;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001355 List<ShortcutInfo> shortcuts;
Kenny Guyb42c89b2014-07-28 19:20:07 +01001356 }
1357
Kenny Guyf939dba2014-08-15 15:32:34 +01001358 public CallbackMessageHandler(Looper looper, LauncherApps.Callback callback) {
Kenny Guyb42c89b2014-07-28 19:20:07 +01001359 super(looper, null, true);
1360 mCallback = callback;
1361 }
1362
1363 @Override
1364 public void handleMessage(Message msg) {
1365 if (mCallback == null || !(msg.obj instanceof CallbackInfo)) {
1366 return;
1367 }
1368 CallbackInfo info = (CallbackInfo) msg.obj;
1369 switch (msg.what) {
1370 case MSG_ADDED:
1371 mCallback.onPackageAdded(info.packageName, info.user);
1372 break;
1373 case MSG_REMOVED:
1374 mCallback.onPackageRemoved(info.packageName, info.user);
1375 break;
1376 case MSG_CHANGED:
1377 mCallback.onPackageChanged(info.packageName, info.user);
1378 break;
1379 case MSG_AVAILABLE:
1380 mCallback.onPackagesAvailable(info.packageNames, info.user, info.replacing);
1381 break;
1382 case MSG_UNAVAILABLE:
1383 mCallback.onPackagesUnavailable(info.packageNames, info.user, info.replacing);
1384 break;
Kenny Guy77242752016-01-15 13:29:06 +00001385 case MSG_SUSPENDED:
Suprabh Shukla96212bc2018-04-10 15:04:51 -07001386 mCallback.onPackagesSuspended(info.packageNames, info.user, info.launcherExtras
1387 );
Kenny Guy77242752016-01-15 13:29:06 +00001388 break;
1389 case MSG_UNSUSPENDED:
1390 mCallback.onPackagesUnsuspended(info.packageNames, info.user);
1391 break;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001392 case MSG_SHORTCUT_CHANGED:
1393 mCallback.onShortcutsChanged(info.packageName, info.shortcuts, info.user);
1394 break;
Kenny Guyb42c89b2014-07-28 19:20:07 +01001395 }
1396 }
1397
1398 public void postOnPackageAdded(String packageName, UserHandle user) {
1399 CallbackInfo info = new CallbackInfo();
1400 info.packageName = packageName;
1401 info.user = user;
1402 obtainMessage(MSG_ADDED, info).sendToTarget();
1403 }
1404
1405 public void postOnPackageRemoved(String packageName, UserHandle user) {
1406 CallbackInfo info = new CallbackInfo();
1407 info.packageName = packageName;
1408 info.user = user;
1409 obtainMessage(MSG_REMOVED, info).sendToTarget();
1410 }
1411
1412 public void postOnPackageChanged(String packageName, UserHandle user) {
1413 CallbackInfo info = new CallbackInfo();
1414 info.packageName = packageName;
1415 info.user = user;
1416 obtainMessage(MSG_CHANGED, info).sendToTarget();
1417 }
1418
1419 public void postOnPackagesAvailable(String[] packageNames, UserHandle user,
1420 boolean replacing) {
1421 CallbackInfo info = new CallbackInfo();
1422 info.packageNames = packageNames;
1423 info.replacing = replacing;
1424 info.user = user;
1425 obtainMessage(MSG_AVAILABLE, info).sendToTarget();
1426 }
1427
1428 public void postOnPackagesUnavailable(String[] packageNames, UserHandle user,
1429 boolean replacing) {
1430 CallbackInfo info = new CallbackInfo();
1431 info.packageNames = packageNames;
1432 info.replacing = replacing;
1433 info.user = user;
1434 obtainMessage(MSG_UNAVAILABLE, info).sendToTarget();
1435 }
Kenny Guy77242752016-01-15 13:29:06 +00001436
Suprabh Shukla19b41f32018-03-26 22:35:13 -07001437 public void postOnPackagesSuspended(String[] packageNames, Bundle launcherExtras,
1438 UserHandle user) {
Kenny Guy77242752016-01-15 13:29:06 +00001439 CallbackInfo info = new CallbackInfo();
1440 info.packageNames = packageNames;
1441 info.user = user;
Suprabh Shukla19b41f32018-03-26 22:35:13 -07001442 info.launcherExtras = launcherExtras;
Kenny Guy77242752016-01-15 13:29:06 +00001443 obtainMessage(MSG_SUSPENDED, info).sendToTarget();
1444 }
1445
1446 public void postOnPackagesUnsuspended(String[] packageNames, UserHandle user) {
1447 CallbackInfo info = new CallbackInfo();
1448 info.packageNames = packageNames;
1449 info.user = user;
1450 obtainMessage(MSG_UNSUSPENDED, info).sendToTarget();
1451 }
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001452
1453 public void postOnShortcutChanged(String packageName, UserHandle user,
1454 List<ShortcutInfo> shortcuts) {
1455 CallbackInfo info = new CallbackInfo();
1456 info.packageName = packageName;
1457 info.user = user;
1458 info.shortcuts = shortcuts;
1459 obtainMessage(MSG_SHORTCUT_CHANGED, info).sendToTarget();
1460 }
Kenny Guyb42c89b2014-07-28 19:20:07 +01001461 }
Makoto Onuki2d895c32016-12-02 15:48:40 -08001462
1463 /**
Jon Miranda2b340a22019-01-25 14:03:49 -08001464 * Register a callback to watch for session lifecycle events in this user and managed profiles.
1465 * @param callback The callback to register.
1466 * @param executor {@link Executor} to handle the callbacks, cannot be null.
1467 *
1468 * @see PackageInstaller#registerSessionCallback(SessionCallback)
1469 */
1470 public void registerPackageInstallerSessionCallback(
1471 @NonNull @CallbackExecutor Executor executor, @NonNull SessionCallback callback) {
1472 if (executor == null) {
1473 throw new NullPointerException("Executor must not be null");
1474 }
1475
1476 synchronized (mDelegates) {
1477 final SessionCallbackDelegate delegate = new SessionCallbackDelegate(callback,
1478 executor);
1479 try {
1480 mService.registerPackageInstallerCallback(mContext.getPackageName(),
1481 delegate);
1482 } catch (RemoteException e) {
1483 throw e.rethrowFromSystemServer();
1484 }
1485 mDelegates.add(delegate);
1486 }
1487 }
1488
1489 /**
1490 * Unregisters a callback that was previously registered.
1491 *
1492 * @param callback The callback to unregister.
1493 * @see #registerPackageInstallerSessionCallback(Executor, SessionCallback)
1494 */
Jon Miranda93505982019-03-08 09:33:42 -08001495 public void unregisterPackageInstallerSessionCallback(@NonNull SessionCallback callback) {
Jon Miranda2b340a22019-01-25 14:03:49 -08001496 synchronized (mDelegates) {
1497 for (Iterator<SessionCallbackDelegate> i = mDelegates.iterator(); i.hasNext();) {
1498 final SessionCallbackDelegate delegate = i.next();
1499 if (delegate.mCallback == callback) {
1500 mPm.getPackageInstaller().unregisterSessionCallback(delegate.mCallback);
1501 i.remove();
1502 }
1503 }
1504 }
1505 }
1506
1507 /**
1508 * Return list of all known install sessions in this user and managed profiles, regardless
1509 * of the installer.
1510 *
1511 * @see PackageInstaller#getAllSessions()
1512 */
1513 public @NonNull List<SessionInfo> getAllPackageInstallerSessions() {
1514 try {
1515 return mService.getAllSessions(mContext.getPackageName()).getList();
1516 } catch (RemoteException e) {
1517 throw e.rethrowFromSystemServer();
1518 }
1519 }
1520
1521 /**
Makoto Onuki2d895c32016-12-02 15:48:40 -08001522 * A helper method to extract a {@link PinItemRequest} set to
1523 * the {@link #EXTRA_PIN_ITEM_REQUEST} extra.
1524 */
1525 public PinItemRequest getPinItemRequest(Intent intent) {
1526 return intent.getParcelableExtra(EXTRA_PIN_ITEM_REQUEST);
1527 }
1528
1529 /**
Sunny Goyal7f7372a2017-01-24 11:53:54 -08001530 * Represents a "pin shortcut" or a "pin appwidget" request made by an app, which is sent with
1531 * an {@link #ACTION_CONFIRM_PIN_SHORTCUT} or {@link #ACTION_CONFIRM_PIN_APPWIDGET} intent
1532 * respectively to the default launcher app.
Makoto Onuki2d895c32016-12-02 15:48:40 -08001533 *
Makoto Onukia37ac3d2017-04-14 12:33:10 -07001534 * <h3>Request of the {@link #REQUEST_TYPE_SHORTCUT} type.
Makoto Onuki0c280712017-01-19 15:14:27 -08001535 *
Makoto Onukia37ac3d2017-04-14 12:33:10 -07001536 * <p>A {@link #REQUEST_TYPE_SHORTCUT} request represents a request to pin a
1537 * {@link ShortcutInfo}. If the launcher accepts a request, call {@link #accept()},
1538 * or {@link #accept(Bundle)} with a null or empty Bundle. No options are defined for
1539 * pin-shortcuts requests.
1540 *
1541 * <p>{@link #getShortcutInfo()} always returns a non-null {@link ShortcutInfo} for this type.
1542 *
1543 * <p>The launcher may receive a request with a {@link ShortcutInfo} that is already pinned, in
1544 * which case {@link ShortcutInfo#isPinned()} returns true. This means the user wants to create
1545 * another pinned shortcut for a shortcut that's already pinned. If the launcher accepts it,
1546 * {@link #accept()} must still be called even though the shortcut is already pinned, and
1547 * create a new pinned shortcut icon for it.
1548 *
1549 * <p>See also {@link ShortcutManager} for more details.
1550 *
1551 * <h3>Request of the {@link #REQUEST_TYPE_APPWIDGET} type.
1552 *
1553 * <p>A {@link #REQUEST_TYPE_SHORTCUT} request represents a request to pin a
1554 * an AppWidget. If the launcher accepts a request, call {@link #accept(Bundle)} with
1555 * the appwidget integer ID set to the
1556 * {@link android.appwidget.AppWidgetManager#EXTRA_APPWIDGET_ID} extra.
1557 *
1558 * <p>{@link #getAppWidgetProviderInfo(Context)} always returns a non-null
1559 * {@link AppWidgetProviderInfo} for this type.
1560 *
1561 * <p>See also {@link AppWidgetManager} for more details.
Sunny Goyal7f7372a2017-01-24 11:53:54 -08001562 *
Makoto Onuki2d895c32016-12-02 15:48:40 -08001563 * @see #EXTRA_PIN_ITEM_REQUEST
1564 * @see #getPinItemRequest(Intent)
1565 */
1566 public static final class PinItemRequest implements Parcelable {
1567
1568 /** This is a request to pin shortcut. */
1569 public static final int REQUEST_TYPE_SHORTCUT = 1;
1570
Sunny Goyal87a563e2017-01-01 19:42:45 -08001571 /** This is a request to pin app widget. */
1572 public static final int REQUEST_TYPE_APPWIDGET = 2;
1573
Makoto Onukif5663b12017-01-09 14:09:56 -08001574 /** @hide */
Jeff Sharkeyce8db992017-12-13 20:05:05 -07001575 @IntDef(prefix = { "REQUEST_TYPE_" }, value = {
1576 REQUEST_TYPE_SHORTCUT,
1577 REQUEST_TYPE_APPWIDGET
1578 })
Makoto Onuki2d895c32016-12-02 15:48:40 -08001579 @Retention(RetentionPolicy.SOURCE)
1580 public @interface RequestType {}
1581
1582 private final int mRequestType;
Makoto Onuki2d895c32016-12-02 15:48:40 -08001583 private final IPinItemRequest mInner;
1584
1585 /**
1586 * @hide
1587 */
Makoto Onuki8abba3a2017-02-24 11:34:54 -08001588 public PinItemRequest(IPinItemRequest inner, int type) {
Sunny Goyal87a563e2017-01-01 19:42:45 -08001589 mInner = inner;
Makoto Onuki8abba3a2017-02-24 11:34:54 -08001590 mRequestType = type;
Makoto Onuki2d895c32016-12-02 15:48:40 -08001591 }
1592
1593 /**
Makoto Onukia37ac3d2017-04-14 12:33:10 -07001594 * Represents the type of a request, which is one of the {@code REQUEST_TYPE_} constants.
1595 *
1596 * @return one of the {@code REQUEST_TYPE_} constants.
Makoto Onuki2d895c32016-12-02 15:48:40 -08001597 */
1598 @RequestType
1599 public int getRequestType() {
1600 return mRequestType;
1601 }
1602
1603 /**
Makoto Onukia37ac3d2017-04-14 12:33:10 -07001604 * {@link ShortcutInfo} sent by the requesting app.
1605 * Always non-null for a {@link #REQUEST_TYPE_SHORTCUT} request, and always null for a
1606 * different request type.
1607 *
1608 * @return requested {@link ShortcutInfo} when a request is of the
1609 * {@link #REQUEST_TYPE_SHORTCUT} type. Null otherwise.
Makoto Onuki2d895c32016-12-02 15:48:40 -08001610 */
1611 @Nullable
1612 public ShortcutInfo getShortcutInfo() {
Makoto Onuki8abba3a2017-02-24 11:34:54 -08001613 try {
1614 return mInner.getShortcutInfo();
1615 } catch (RemoteException e) {
1616 throw e.rethrowAsRuntimeException();
1617 }
Makoto Onuki2d895c32016-12-02 15:48:40 -08001618 }
1619
1620 /**
Makoto Onukia37ac3d2017-04-14 12:33:10 -07001621 * {@link AppWidgetProviderInfo} sent by the requesting app.
1622 * Always non-null for a {@link #REQUEST_TYPE_APPWIDGET} request, and always null for a
1623 * different request type.
1624 *
Sunny Goyale7712ad2018-03-08 11:23:06 -08001625 * <p>Launcher should not show any configuration activity associated with the provider, and
1626 * assume that the widget is already fully configured. Upon accepting the widget, it should
1627 * pass the widgetId in {@link #accept(Bundle)}.
1628 *
Makoto Onukia37ac3d2017-04-14 12:33:10 -07001629 * @return requested {@link AppWidgetProviderInfo} when a request is of the
1630 * {@link #REQUEST_TYPE_APPWIDGET} type. Null otherwise.
Sunny Goyal87a563e2017-01-01 19:42:45 -08001631 */
1632 @Nullable
Sunny Goyal970d4b42017-01-19 15:07:36 -08001633 public AppWidgetProviderInfo getAppWidgetProviderInfo(Context context) {
Makoto Onuki8abba3a2017-02-24 11:34:54 -08001634 try {
1635 final AppWidgetProviderInfo info = mInner.getAppWidgetProviderInfo();
1636 if (info == null) {
1637 return null;
1638 }
Sunny Goyal970d4b42017-01-19 15:07:36 -08001639 info.updateDimensions(context.getResources().getDisplayMetrics());
1640 return info;
Makoto Onuki8abba3a2017-02-24 11:34:54 -08001641 } catch (RemoteException e) {
1642 throw e.rethrowAsRuntimeException();
Sunny Goyal970d4b42017-01-19 15:07:36 -08001643 }
Sunny Goyal87a563e2017-01-01 19:42:45 -08001644 }
1645
1646 /**
Sunny Goyal4ad6b572017-02-28 11:11:51 -08001647 * Any extras sent by the requesting app.
Makoto Onukia37ac3d2017-04-14 12:33:10 -07001648 *
1649 * @return For a shortcut request, this method always return null. For an AppWidget
1650 * request, this method returns the extras passed to the
1651 * {@link android.appwidget.AppWidgetManager#requestPinAppWidget(
1652 * ComponentName, Bundle, PendingIntent)} API. See {@link AppWidgetManager} for details.
Sunny Goyal4ad6b572017-02-28 11:11:51 -08001653 */
1654 @Nullable
1655 public Bundle getExtras() {
1656 try {
1657 return mInner.getExtras();
1658 } catch (RemoteException e) {
1659 throw e.rethrowAsRuntimeException();
1660 }
1661 }
1662
1663 /**
Makoto Onukia37ac3d2017-04-14 12:33:10 -07001664 * Return whether a request is still valid.
1665 *
1666 * @return {@code TRUE} if a request is valid and {@link #accept(Bundle)} may be called.
Makoto Onuki2d895c32016-12-02 15:48:40 -08001667 */
1668 public boolean isValid() {
1669 try {
1670 return mInner.isValid();
1671 } catch (RemoteException e) {
1672 return false;
1673 }
1674 }
1675
1676 /**
1677 * Called by the receiving launcher app when the user accepts the request.
Makoto Onukia37ac3d2017-04-14 12:33:10 -07001678 *
1679 * @param options must be set for a {@link #REQUEST_TYPE_APPWIDGET} request.
1680 *
1681 * @return {@code TRUE} if the shortcut or the AppWidget has actually been pinned.
1682 * {@code FALSE} if the item hasn't been pinned, for example, because the request had
1683 * already been canceled, in which case the launcher must not pin the requested item.
Makoto Onuki2d895c32016-12-02 15:48:40 -08001684 */
1685 public boolean accept(@Nullable Bundle options) {
1686 try {
1687 return mInner.accept(options);
1688 } catch (RemoteException e) {
1689 throw e.rethrowFromSystemServer();
1690 }
1691 }
1692
1693 /**
Makoto Onukia37ac3d2017-04-14 12:33:10 -07001694 * Called by the receiving launcher app when the user accepts the request, with no options.
1695 *
1696 * @return {@code TRUE} if the shortcut or the AppWidget has actually been pinned.
1697 * {@code FALSE} if the item hasn't been pinned, for example, because the request had
1698 * already been canceled, in which case the launcher must not pin the requested item.
Makoto Onuki2d895c32016-12-02 15:48:40 -08001699 */
1700 public boolean accept() {
1701 return accept(/* options= */ null);
1702 }
1703
1704 private PinItemRequest(Parcel source) {
1705 final ClassLoader cl = getClass().getClassLoader();
1706
1707 mRequestType = source.readInt();
Makoto Onuki2d895c32016-12-02 15:48:40 -08001708 mInner = IPinItemRequest.Stub.asInterface(source.readStrongBinder());
1709 }
1710
1711 @Override
1712 public void writeToParcel(Parcel dest, int flags) {
1713 dest.writeInt(mRequestType);
Makoto Onuki2d895c32016-12-02 15:48:40 -08001714 dest.writeStrongBinder(mInner.asBinder());
1715 }
1716
Jeff Sharkey9e8f83d2019-02-28 12:06:45 -07001717 public static final @android.annotation.NonNull Creator<PinItemRequest> CREATOR =
Makoto Onuki2d895c32016-12-02 15:48:40 -08001718 new Creator<PinItemRequest>() {
1719 public PinItemRequest createFromParcel(Parcel source) {
1720 return new PinItemRequest(source);
1721 }
1722 public PinItemRequest[] newArray(int size) {
1723 return new PinItemRequest[size];
1724 }
1725 };
1726
1727 @Override
1728 public int describeContents() {
1729 return 0;
1730 }
1731 }
Varun Shah2546cef2019-01-11 15:50:54 -08001732
1733 /**
1734 * A class that encapsulates information about the usage limit set for an app or
1735 * a group of apps.
1736 *
Varun Shah9c6f72b2019-01-25 21:13:56 -08001737 * <p>The launcher can query specifics about the usage limit such as how much usage time
1738 * the limit has and how much of the total usage time is remaining via the APIs available
1739 * in this class.
Varun Shah2546cef2019-01-11 15:50:54 -08001740 *
1741 * @see #getAppUsageLimit(String, UserHandle)
1742 */
1743 public static final class AppUsageLimit implements Parcelable {
Varun Shah2546cef2019-01-11 15:50:54 -08001744 private final long mTotalUsageLimit;
1745 private final long mUsageRemaining;
1746
1747 /** @hide */
Varun Shah9c6f72b2019-01-25 21:13:56 -08001748 public AppUsageLimit(long totalUsageLimit, long usageRemaining) {
Varun Shah2546cef2019-01-11 15:50:54 -08001749 this.mTotalUsageLimit = totalUsageLimit;
1750 this.mUsageRemaining = usageRemaining;
1751 }
1752
1753 /**
Varun Shah2546cef2019-01-11 15:50:54 -08001754 * Returns the total usage limit in milliseconds set for an app or a group of apps.
1755 *
1756 * @return the total usage limit in milliseconds
1757 */
1758 public long getTotalUsageLimit() {
1759 return mTotalUsageLimit;
1760 }
1761
1762 /**
1763 * Returns the usage remaining in milliseconds for an app or the group of apps
1764 * this limit refers to.
1765 *
1766 * @return the usage remaining in milliseconds
1767 */
1768 public long getUsageRemaining() {
1769 return mUsageRemaining;
1770 }
1771
1772 private AppUsageLimit(Parcel source) {
Varun Shah2546cef2019-01-11 15:50:54 -08001773 mTotalUsageLimit = source.readLong();
1774 mUsageRemaining = source.readLong();
1775 }
1776
Jeff Sharkey9e8f83d2019-02-28 12:06:45 -07001777 public static final @android.annotation.NonNull Creator<AppUsageLimit> CREATOR = new Creator<AppUsageLimit>() {
Varun Shah2546cef2019-01-11 15:50:54 -08001778 @Override
1779 public AppUsageLimit createFromParcel(Parcel source) {
1780 return new AppUsageLimit(source);
1781 }
1782
1783 @Override
1784 public AppUsageLimit[] newArray(int size) {
1785 return new AppUsageLimit[size];
1786 }
1787 };
1788
1789 @Override
1790 public int describeContents() {
1791 return 0;
1792 }
1793
1794 @Override
1795 public void writeToParcel(Parcel dest, int flags) {
Varun Shah2546cef2019-01-11 15:50:54 -08001796 dest.writeLong(mTotalUsageLimit);
1797 dest.writeLong(mUsageRemaining);
1798 }
1799 }
Amith Yamasani4f582632014-02-19 14:31:52 -08001800}