blob: b94a410b0ba0e765c5df32d11601bf8b24251c9c [file] [log] [blame]
Amith Yamasani4f582632014-02-19 14:31:52 -08001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.content.pm;
18
Makoto Onuki6f7362d92016-03-04 13:39:41 -080019import android.annotation.IntDef;
20import android.annotation.NonNull;
21import android.annotation.Nullable;
Makoto Onuki2d895c32016-12-02 15:48:40 -080022import android.annotation.SdkConstant;
23import android.annotation.SdkConstant.SdkConstantType;
Makoto Onukib1588c02017-10-12 15:11:45 -070024import android.annotation.SystemService;
Makoto Onuki5ba0d3e2016-04-11 14:03:46 -070025import android.annotation.TestApi;
Makoto Onukia37ac3d2017-04-14 12:33:10 -070026import android.app.PendingIntent;
27import android.appwidget.AppWidgetManager;
Sunny Goyal87a563e2017-01-01 19:42:45 -080028import android.appwidget.AppWidgetProviderInfo;
Makoto Onuki83f6d2d2016-07-11 14:30:19 -070029import android.content.ActivityNotFoundException;
Amith Yamasani4f582632014-02-19 14:31:52 -080030import android.content.ComponentName;
31import android.content.Context;
32import android.content.Intent;
Sunny Goyala6be88a2017-01-12 16:27:58 -080033import android.content.IntentSender;
Kenny Guy77242752016-01-15 13:29:06 +000034import android.content.pm.PackageManager.ApplicationInfoFlags;
Makoto Onuki04b9aab2016-05-23 17:13:30 -070035import android.content.pm.PackageManager.NameNotFoundException;
36import android.content.res.Resources;
37import android.graphics.Bitmap;
38import android.graphics.BitmapFactory;
Amith Yamasani4f582632014-02-19 14:31:52 -080039import android.graphics.Rect;
Makoto Onukib1588c02017-10-12 15:11:45 -070040import android.graphics.drawable.AdaptiveIconDrawable;
Makoto Onuki04b9aab2016-05-23 17:13:30 -070041import android.graphics.drawable.BitmapDrawable;
Makoto Onuki20c95f82016-05-11 16:51:01 -070042import android.graphics.drawable.Drawable;
Makoto Onuki2d895c32016-12-02 15:48:40 -080043import android.graphics.drawable.Icon;
Amith Yamasani4f582632014-02-19 14:31:52 -080044import android.os.Bundle;
Kenny Guyb42c89b2014-07-28 19:20:07 +010045import android.os.Handler;
46import android.os.Looper;
47import android.os.Message;
Makoto Onuki2d895c32016-12-02 15:48:40 -080048import android.os.Parcel;
Makoto Onuki6f7362d92016-03-04 13:39:41 -080049import android.os.ParcelFileDescriptor;
Makoto Onuki2d895c32016-12-02 15:48:40 -080050import android.os.Parcelable;
Amith Yamasani4f582632014-02-19 14:31:52 -080051import android.os.RemoteException;
Makoto Onuki5ba0d3e2016-04-11 14:03:46 -070052import android.os.ServiceManager;
Amith Yamasani4f582632014-02-19 14:31:52 -080053import android.os.UserHandle;
Amith Yamasanie781c812014-05-28 15:28:18 -070054import android.os.UserManager;
Makoto Onuki04b9aab2016-05-23 17:13:30 -070055import android.util.DisplayMetrics;
Amith Yamasani4f582632014-02-19 14:31:52 -080056import android.util.Log;
57
Makoto Onuki7c7fbf62017-04-14 11:03:56 -070058import com.android.internal.util.Preconditions;
59
Makoto Onuki04b9aab2016-05-23 17:13:30 -070060import java.io.IOException;
Makoto Onuki6f7362d92016-03-04 13:39:41 -080061import java.lang.annotation.Retention;
62import java.lang.annotation.RetentionPolicy;
Amith Yamasani4f582632014-02-19 14:31:52 -080063import java.util.ArrayList;
Makoto Onukib6d35232016-04-04 15:57:17 -070064import java.util.Arrays;
Amith Yamasani4f582632014-02-19 14:31:52 -080065import java.util.Collections;
66import java.util.List;
67
68/**
69 * Class for retrieving a list of launchable activities for the current user and any associated
Makoto Onukiaecbd032017-01-19 12:11:11 -080070 * managed profiles that are visible to the current user, which can be retrieved with
71 * {@link #getProfiles}. This is mainly for use by launchers.
72 *
73 * Apps can be queried for each user profile.
Amith Yamasani4f582632014-02-19 14:31:52 -080074 * Since the PackageManager will not deliver package broadcasts for other profiles, you can register
75 * for package changes here.
Amith Yamasanie781c812014-05-28 15:28:18 -070076 * <p>
77 * To watch for managed profiles being added or removed, register for the following broadcasts:
78 * {@link Intent#ACTION_MANAGED_PROFILE_ADDED} and {@link Intent#ACTION_MANAGED_PROFILE_REMOVED}.
79 * <p>
Makoto Onukiaecbd032017-01-19 12:11:11 -080080 * Note as of Android O, apps on a managed profile are no longer allowed to access apps on the
81 * main profile. Apps can only access profiles returned by {@link #getProfiles()}.
Amith Yamasani4f582632014-02-19 14:31:52 -080082 */
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -060083@SystemService(Context.LAUNCHER_APPS_SERVICE)
Amith Yamasani4f582632014-02-19 14:31:52 -080084public class LauncherApps {
85
86 static final String TAG = "LauncherApps";
87 static final boolean DEBUG = false;
88
Makoto Onuki2d895c32016-12-02 15:48:40 -080089 /**
90 * Activity Action: For the default launcher to show the confirmation dialog to create
91 * a pinned shortcut.
92 *
93 * <p>See the {@link ShortcutManager} javadoc for details.
94 *
95 * <p>
96 * Use {@link #getPinItemRequest(Intent)} to get a {@link PinItemRequest} object,
97 * and call {@link PinItemRequest#accept(Bundle)}
98 * if the user accepts. If the user doesn't accept, no further action is required.
99 *
100 * @see #EXTRA_PIN_ITEM_REQUEST
101 */
102 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
Sunny Goyal7f7372a2017-01-24 11:53:54 -0800103 public static final String ACTION_CONFIRM_PIN_SHORTCUT =
104 "android.content.pm.action.CONFIRM_PIN_SHORTCUT";
Makoto Onuki2d895c32016-12-02 15:48:40 -0800105
106 /**
Sunny Goyal7f7372a2017-01-24 11:53:54 -0800107 * Activity Action: For the default launcher to show the confirmation dialog to create
108 * a pinned app widget.
109 *
110 * <p>See the {@link android.appwidget.AppWidgetManager#requestPinAppWidget} javadoc for
111 * details.
112 *
113 * <p>
114 * Use {@link #getPinItemRequest(Intent)} to get a {@link PinItemRequest} object,
115 * and call {@link PinItemRequest#accept(Bundle)}
116 * if the user accepts. If the user doesn't accept, no further action is required.
117 *
118 * @see #EXTRA_PIN_ITEM_REQUEST
119 */
120 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
121 public static final String ACTION_CONFIRM_PIN_APPWIDGET =
122 "android.content.pm.action.CONFIRM_PIN_APPWIDGET";
123
124 /**
125 * An extra for {@link #ACTION_CONFIRM_PIN_SHORTCUT} &amp; {@link #ACTION_CONFIRM_PIN_APPWIDGET}
126 * containing a {@link PinItemRequest} of appropriate type asked to pin.
Makoto Onuki2d895c32016-12-02 15:48:40 -0800127 *
128 * <p>A helper function {@link #getPinItemRequest(Intent)} can be used
129 * instead of using this constant directly.
130 *
Sunny Goyal7f7372a2017-01-24 11:53:54 -0800131 * @see #ACTION_CONFIRM_PIN_SHORTCUT
132 * @see #ACTION_CONFIRM_PIN_APPWIDGET
Makoto Onuki2d895c32016-12-02 15:48:40 -0800133 */
134 public static final String EXTRA_PIN_ITEM_REQUEST =
135 "android.content.pm.extra.PIN_ITEM_REQUEST";
136
Makoto Onukide3c16c2017-01-26 11:39:31 -0800137 private final Context mContext;
138 private final ILauncherApps mService;
139 private final PackageManager mPm;
140 private final UserManager mUserManager;
Amith Yamasani4f582632014-02-19 14:31:52 -0800141
Kenny Guyb42c89b2014-07-28 19:20:07 +0100142 private List<CallbackMessageHandler> mCallbacks
143 = new ArrayList<CallbackMessageHandler>();
Kenny Guyc01545372014-06-16 14:17:26 +0100144
145 /**
146 * Callbacks for package changes to this and related managed profiles.
147 */
Kenny Guyf939dba2014-08-15 15:32:34 +0100148 public static abstract class Callback {
Kenny Guyc01545372014-06-16 14:17:26 +0100149 /**
150 * Indicates that a package was removed from the specified profile.
151 *
Kenny Guyb42c89b2014-07-28 19:20:07 +0100152 * If a package is removed while being updated onPackageChanged will be
153 * called instead.
154 *
Kenny Guyc01545372014-06-16 14:17:26 +0100155 * @param packageName The name of the package that was removed.
156 * @param user The UserHandle of the profile that generated the change.
157 */
158 abstract public void onPackageRemoved(String packageName, UserHandle user);
159
160 /**
161 * Indicates that a package was added to the specified profile.
162 *
Kenny Guyb42c89b2014-07-28 19:20:07 +0100163 * If a package is added while being updated then onPackageChanged will be
164 * called instead.
165 *
Kenny Guyc01545372014-06-16 14:17:26 +0100166 * @param packageName The name of the package that was added.
167 * @param user The UserHandle of the profile that generated the change.
168 */
169 abstract public void onPackageAdded(String packageName, UserHandle user);
170
171 /**
172 * Indicates that a package was modified in the specified profile.
Kenny Guyb42c89b2014-07-28 19:20:07 +0100173 * This can happen, for example, when the package is updated or when
174 * one or more components are enabled or disabled.
Kenny Guyc01545372014-06-16 14:17:26 +0100175 *
176 * @param packageName The name of the package that has changed.
177 * @param user The UserHandle of the profile that generated the change.
178 */
179 abstract public void onPackageChanged(String packageName, UserHandle user);
180
181 /**
182 * Indicates that one or more packages have become available. For
183 * example, this can happen when a removable storage card has
184 * reappeared.
185 *
186 * @param packageNames The names of the packages that have become
187 * available.
188 * @param user The UserHandle of the profile that generated the change.
189 * @param replacing Indicates whether these packages are replacing
190 * existing ones.
191 */
192 abstract public void onPackagesAvailable(String[] packageNames, UserHandle user,
193 boolean replacing);
194
195 /**
196 * Indicates that one or more packages have become unavailable. For
197 * example, this can happen when a removable storage card has been
198 * removed.
199 *
200 * @param packageNames The names of the packages that have become
201 * unavailable.
202 * @param user The UserHandle of the profile that generated the change.
203 * @param replacing Indicates whether the packages are about to be
204 * replaced with new versions.
205 */
206 abstract public void onPackagesUnavailable(String[] packageNames, UserHandle user,
207 boolean replacing);
Kenny Guy77242752016-01-15 13:29:06 +0000208
209 /**
210 * Indicates that one or more packages have been suspended. For
211 * example, this can happen when a Device Administrator suspends
212 * an applicaton.
213 *
214 * @param packageNames The names of the packages that have just been
215 * suspended.
216 * @param user The UserHandle of the profile that generated the change.
217 */
218 public void onPackagesSuspended(String[] packageNames, UserHandle user) {
219 }
220
221 /**
222 * Indicates that one or more packages have been unsuspended. For
223 * example, this can happen when a Device Administrator unsuspends
224 * an applicaton.
225 *
226 * @param packageNames The names of the packages that have just been
227 * unsuspended.
228 * @param user The UserHandle of the profile that generated the change.
229 */
230 public void onPackagesUnsuspended(String[] packageNames, UserHandle user) {
231 }
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800232
233 /**
Makoto Onukife9c9662016-07-25 15:12:23 -0700234 * Indicates that one or more shortcuts of any kind (dynamic, pinned, or manifest)
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800235 * have been added, updated or removed.
236 *
Makoto Onuki2d5b4652016-03-11 16:09:54 -0800237 * <p>Only the applications that are allowed to access the shortcut information,
238 * as defined in {@link #hasShortcutHostPermission()}, will receive it.
239 *
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800240 * @param packageName The name of the package that has the shortcuts.
Makoto Onukife9c9662016-07-25 15:12:23 -0700241 * @param shortcuts All shortcuts from the package (dynamic, manifest and/or pinned).
242 * Only "key" information will be provided, as defined in
Makoto Onuki4d6b87f2016-06-17 13:47:40 -0700243 * {@link ShortcutInfo#hasKeyFieldsOnly()}.
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800244 * @param user The UserHandle of the profile that generated the change.
Makoto Onuki4a910962016-07-07 13:57:34 -0700245 *
246 * @see ShortcutManager
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800247 */
248 public void onShortcutsChanged(@NonNull String packageName,
249 @NonNull List<ShortcutInfo> shortcuts, @NonNull UserHandle user) {
250 }
251 }
252
253 /**
254 * Represents a query passed to {@link #getShortcuts(ShortcutQuery, UserHandle)}.
255 */
256 public static class ShortcutQuery {
257 /**
258 * Include dynamic shortcuts in the result.
259 */
Makoto Onukib5a012f2016-06-21 11:13:53 -0700260 public static final int FLAG_MATCH_DYNAMIC = 1 << 0;
261
262 /** @hide kept for unit tests */
263 @Deprecated
264 public static final int FLAG_GET_DYNAMIC = FLAG_MATCH_DYNAMIC;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800265
266 /**
267 * Include pinned shortcuts in the result.
268 */
Makoto Onukib5a012f2016-06-21 11:13:53 -0700269 public static final int FLAG_MATCH_PINNED = 1 << 1;
270
271 /** @hide kept for unit tests */
272 @Deprecated
273 public static final int FLAG_GET_PINNED = FLAG_MATCH_PINNED;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800274
275 /**
Makoto Onuki22fcc682016-05-17 14:52:19 -0700276 * Include manifest shortcuts in the result.
277 */
Makoto Onukib5a012f2016-06-21 11:13:53 -0700278 public static final int FLAG_MATCH_MANIFEST = 1 << 3;
279
280 /** @hide kept for unit tests */
281 @Deprecated
282 public static final int FLAG_GET_MANIFEST = FLAG_MATCH_MANIFEST;
Makoto Onuki22fcc682016-05-17 14:52:19 -0700283
Hakan Seyalioglu58fc95d2016-12-13 15:23:22 -0800284 /**
Makoto Onuki634cecb2017-10-13 17:10:48 -0700285 * @hide include all pinned shortcuts by any launchers, not just by the caller,
286 * in the result.
287 * If the caller doesn't havve the {@link android.Manifest.permission#ACCESS_SHORTCUTS}
288 * permission, this flag will be ignored.
289 */
290 @TestApi
291 public static final int FLAG_MATCH_ALL_PINNED = 1 << 10;
292
293 /**
294 * FLAG_MATCH_DYNAMIC | FLAG_MATCH_PINNED | FLAG_MATCH_MANIFEST
Hakan Seyalioglu58fc95d2016-12-13 15:23:22 -0800295 * @hide
296 */
Makoto Onukib5a012f2016-06-21 11:13:53 -0700297 public static final int FLAG_MATCH_ALL_KINDS =
Makoto Onuki634cecb2017-10-13 17:10:48 -0700298 FLAG_MATCH_DYNAMIC | FLAG_MATCH_PINNED | FLAG_MATCH_MANIFEST;
299
300 /**
301 * FLAG_MATCH_DYNAMIC | FLAG_MATCH_PINNED | FLAG_MATCH_MANIFEST | FLAG_MATCH_ALL_PINNED
302 * @hide
303 */
304 public static final int FLAG_MATCH_ALL_KINDS_WITH_ALL_PINNED =
305 FLAG_MATCH_ALL_KINDS | FLAG_MATCH_ALL_PINNED;
Makoto Onuki4d6b87f2016-06-17 13:47:40 -0700306
Makoto Onukib5a012f2016-06-21 11:13:53 -0700307 /** @hide kept for unit tests */
308 @Deprecated
309 public static final int FLAG_GET_ALL_KINDS = FLAG_MATCH_ALL_KINDS;
310
Makoto Onuki22fcc682016-05-17 14:52:19 -0700311 /**
Makoto Onukife9c9662016-07-25 15:12:23 -0700312 * Requests "key" fields only. See {@link ShortcutInfo#hasKeyFieldsOnly()}'s javadoc to
313 * see which fields fields "key".
314 * This allows quicker access to shortcut information in order to
315 * determine whether the caller's in-memory cache needs to be updated.
Makoto Onuki4a910962016-07-07 13:57:34 -0700316 *
Makoto Onukife9c9662016-07-25 15:12:23 -0700317 * <p>Typically, launcher applications cache all or most shortcut information
318 * in memory in order to show shortcuts without a delay.
319 *
320 * When a given launcher application wants to update its cache, such as when its process
321 * restarts, it can fetch shortcut information with this flag.
322 * The application can then check {@link ShortcutInfo#getLastChangedTimestamp()} for each
323 * shortcut, fetching a shortcut's non-key information only if that shortcut has been
324 * updated.
Makoto Onuki4a910962016-07-07 13:57:34 -0700325 *
326 * @see ShortcutManager
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800327 */
328 public static final int FLAG_GET_KEY_FIELDS_ONLY = 1 << 2;
329
330 /** @hide */
331 @IntDef(flag = true,
332 value = {
Makoto Onukib5a012f2016-06-21 11:13:53 -0700333 FLAG_MATCH_DYNAMIC,
334 FLAG_MATCH_PINNED,
335 FLAG_MATCH_MANIFEST,
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800336 FLAG_GET_KEY_FIELDS_ONLY,
Makoto Onuki634cecb2017-10-13 17:10:48 -0700337 FLAG_MATCH_MANIFEST,
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800338 })
339 @Retention(RetentionPolicy.SOURCE)
340 public @interface QueryFlags {}
341
342 long mChangedSince;
343
344 @Nullable
345 String mPackage;
346
347 @Nullable
Makoto Onukiabe84422016-04-07 09:41:19 -0700348 List<String> mShortcutIds;
349
350 @Nullable
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800351 ComponentName mActivity;
352
353 @QueryFlags
354 int mQueryFlags;
355
356 public ShortcutQuery() {
357 }
358
359 /**
Makoto Onukife9c9662016-07-25 15:12:23 -0700360 * If non-zero, returns only shortcuts that have been added or updated
361 * since the given timestamp, expressed in milliseconds since the Epoch&mdash;see
362 * {@link System#currentTimeMillis()}.
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800363 */
Makoto Onuki22fcc682016-05-17 14:52:19 -0700364 public ShortcutQuery setChangedSince(long changedSince) {
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800365 mChangedSince = changedSince;
Makoto Onuki22fcc682016-05-17 14:52:19 -0700366 return this;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800367 }
368
369 /**
370 * If non-null, returns only shortcuts from the package.
371 */
Makoto Onuki22fcc682016-05-17 14:52:19 -0700372 public ShortcutQuery setPackage(@Nullable String packageName) {
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800373 mPackage = packageName;
Makoto Onuki22fcc682016-05-17 14:52:19 -0700374 return this;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800375 }
376
377 /**
Makoto Onukiabe84422016-04-07 09:41:19 -0700378 * If non-null, return only the specified shortcuts by ID. When setting this field,
Makoto Onuki4a910962016-07-07 13:57:34 -0700379 * a package name must also be set with {@link #setPackage}.
Makoto Onukiabe84422016-04-07 09:41:19 -0700380 */
Makoto Onuki22fcc682016-05-17 14:52:19 -0700381 public ShortcutQuery setShortcutIds(@Nullable List<String> shortcutIds) {
Makoto Onukiabe84422016-04-07 09:41:19 -0700382 mShortcutIds = shortcutIds;
Makoto Onuki22fcc682016-05-17 14:52:19 -0700383 return this;
Makoto Onukiabe84422016-04-07 09:41:19 -0700384 }
385
386 /**
Makoto Onuki22fcc682016-05-17 14:52:19 -0700387 * If non-null, returns only shortcuts associated with the activity; i.e.
388 * {@link ShortcutInfo}s whose {@link ShortcutInfo#getActivity()} are equal
389 * to {@code activity}.
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800390 */
Makoto Onuki22fcc682016-05-17 14:52:19 -0700391 public ShortcutQuery setActivity(@Nullable ComponentName activity) {
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800392 mActivity = activity;
Makoto Onuki22fcc682016-05-17 14:52:19 -0700393 return this;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800394 }
395
Hakan Seyalioglu58fc95d2016-12-13 15:23:22 -0800396 /**
Makoto Onukife9c9662016-07-25 15:12:23 -0700397 * Set query options. At least one of the {@code MATCH} flags should be set. Otherwise,
398 * no shortcuts will be returned.
Makoto Onuki4a910962016-07-07 13:57:34 -0700399 *
Makoto Onukife9c9662016-07-25 15:12:23 -0700400 * <ul>
401 * <li>{@link #FLAG_MATCH_DYNAMIC}
402 * <li>{@link #FLAG_MATCH_PINNED}
403 * <li>{@link #FLAG_MATCH_MANIFEST}
404 * <li>{@link #FLAG_GET_KEY_FIELDS_ONLY}
405 * </ul>
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800406 */
Makoto Onuki22fcc682016-05-17 14:52:19 -0700407 public ShortcutQuery setQueryFlags(@QueryFlags int queryFlags) {
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800408 mQueryFlags = queryFlags;
Makoto Onuki22fcc682016-05-17 14:52:19 -0700409 return this;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800410 }
Kenny Guyc01545372014-06-16 14:17:26 +0100411 }
Amith Yamasani4f582632014-02-19 14:31:52 -0800412
Amith Yamasani4f582632014-02-19 14:31:52 -0800413 /** @hide */
414 public LauncherApps(Context context, ILauncherApps service) {
415 mContext = context;
416 mService = service;
Amith Yamasanie781c812014-05-28 15:28:18 -0700417 mPm = context.getPackageManager();
Makoto Onukide3c16c2017-01-26 11:39:31 -0800418 mUserManager = context.getSystemService(UserManager.class);
Amith Yamasani4f582632014-02-19 14:31:52 -0800419 }
420
Makoto Onuki5ba0d3e2016-04-11 14:03:46 -0700421 /** @hide */
422 @TestApi
423 public LauncherApps(Context context) {
424 this(context, ILauncherApps.Stub.asInterface(
425 ServiceManager.getService(Context.LAUNCHER_APPS_SERVICE)));
426 }
427
Amith Yamasani4f582632014-02-19 14:31:52 -0800428 /**
Makoto Onukide3c16c2017-01-26 11:39:31 -0800429 * Show an error log on logcat, when the calling user is a managed profile, and the target
430 * user is different from the calling user, in order to help developers to detect it.
431 */
432 private void logErrorForInvalidProfileAccess(@NonNull UserHandle target) {
433 if (UserHandle.myUserId() != target.getIdentifier() && mUserManager.isManagedProfile()) {
Makoto Onuki3cc7cd12017-04-03 12:48:42 -0700434 Log.w(TAG, "Accessing other profiles/users from managed profile is no longer allowed.");
Makoto Onukide3c16c2017-01-26 11:39:31 -0800435 }
436 }
437
438 /**
Makoto Onukiaecbd032017-01-19 12:11:11 -0800439 * Return a list of profiles that the caller can access via the {@link LauncherApps} APIs.
440 *
441 * <p>If the caller is running on a managed profile, it'll return only the current profile.
442 * Otherwise it'll return the same list as {@link UserManager#getUserProfiles()} would.
443 */
444 public List<UserHandle> getProfiles() {
Makoto Onukide3c16c2017-01-26 11:39:31 -0800445 if (mUserManager.isManagedProfile()) {
Makoto Onukiaecbd032017-01-19 12:11:11 -0800446 // If it's a managed profile, only return the current profile.
447 final List result = new ArrayList(1);
448 result.add(android.os.Process.myUserHandle());
449 return result;
450 } else {
Makoto Onukide3c16c2017-01-26 11:39:31 -0800451 return mUserManager.getUserProfiles();
Makoto Onukiaecbd032017-01-19 12:11:11 -0800452 }
453 }
454
455 /**
Amith Yamasani4f582632014-02-19 14:31:52 -0800456 * Retrieves a list of launchable activities that match {@link Intent#ACTION_MAIN} and
457 * {@link Intent#CATEGORY_LAUNCHER}, for a specified user.
458 *
459 * @param packageName The specific package to query. If null, it checks all installed packages
460 * in the profile.
461 * @param user The UserHandle of the profile.
462 * @return List of launchable activities. Can be an empty list but will not be null.
463 */
464 public List<LauncherActivityInfo> getActivityList(String packageName, UserHandle user) {
Makoto Onukide3c16c2017-01-26 11:39:31 -0800465 logErrorForInvalidProfileAccess(user);
Amith Yamasani4f582632014-02-19 14:31:52 -0800466 try {
Makoto Onuki3a2541e2017-01-24 09:00:15 -0800467 return convertToActivityList(mService.getLauncherActivities(mContext.getPackageName(),
468 packageName, user), user);
Amith Yamasani4f582632014-02-19 14:31:52 -0800469 } catch (RemoteException re) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700470 throw re.rethrowFromSystemServer();
Amith Yamasani4f582632014-02-19 14:31:52 -0800471 }
Amith Yamasani4f582632014-02-19 14:31:52 -0800472 }
473
Amith Yamasani4f582632014-02-19 14:31:52 -0800474 /**
475 * Returns the activity info for a given intent and user handle, if it resolves. Otherwise it
476 * returns null.
477 *
478 * @param intent The intent to find a match for.
479 * @param user The profile to look in for a match.
480 * @return An activity info object if there is a match.
481 */
482 public LauncherActivityInfo resolveActivity(Intent intent, UserHandle user) {
Makoto Onukide3c16c2017-01-26 11:39:31 -0800483 logErrorForInvalidProfileAccess(user);
Amith Yamasani4f582632014-02-19 14:31:52 -0800484 try {
Makoto Onuki3a2541e2017-01-24 09:00:15 -0800485 ActivityInfo ai = mService.resolveActivity(mContext.getPackageName(),
486 intent.getComponent(), user);
Sunny Goyal45d3e972016-03-31 12:38:17 -0700487 if (ai != null) {
488 LauncherActivityInfo info = new LauncherActivityInfo(mContext, ai, user);
Amith Yamasani4f582632014-02-19 14:31:52 -0800489 return info;
490 }
491 } catch (RemoteException re) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700492 throw re.rethrowFromSystemServer();
Amith Yamasani4f582632014-02-19 14:31:52 -0800493 }
494 return null;
495 }
496
497 /**
Kenny Guyf939dba2014-08-15 15:32:34 +0100498 * Starts a Main activity in the specified profile.
Amith Yamasani4f582632014-02-19 14:31:52 -0800499 *
500 * @param component The ComponentName of the activity to launch
Amith Yamasanie781c812014-05-28 15:28:18 -0700501 * @param user The UserHandle of the profile
502 * @param sourceBounds The Rect containing the source bounds of the clicked icon
503 * @param opts Options to pass to startActivity
504 */
Kenny Guyf939dba2014-08-15 15:32:34 +0100505 public void startMainActivity(ComponentName component, UserHandle user, Rect sourceBounds,
Amith Yamasanie781c812014-05-28 15:28:18 -0700506 Bundle opts) {
Makoto Onukide3c16c2017-01-26 11:39:31 -0800507 logErrorForInvalidProfileAccess(user);
Amith Yamasani5abdbb62014-04-08 17:23:46 -0700508 if (DEBUG) {
Kenny Guyf939dba2014-08-15 15:32:34 +0100509 Log.i(TAG, "StartMainActivity " + component + " " + user.getIdentifier());
Amith Yamasani5abdbb62014-04-08 17:23:46 -0700510 }
Amith Yamasani4f582632014-02-19 14:31:52 -0800511 try {
Makoto Onuki3a2541e2017-01-24 09:00:15 -0800512 mService.startActivityAsUser(mContext.getPackageName(),
513 component, sourceBounds, opts, user);
Amith Yamasani4f582632014-02-19 14:31:52 -0800514 } catch (RemoteException re) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700515 throw re.rethrowFromSystemServer();
Amith Yamasani4f582632014-02-19 14:31:52 -0800516 }
517 }
518
519 /**
Kenny Guy466d2032014-07-23 12:23:35 +0100520 * Starts the settings activity to show the application details for a
521 * package in the specified profile.
522 *
523 * @param component The ComponentName of the package to launch settings for.
524 * @param user The UserHandle of the profile
525 * @param sourceBounds The Rect containing the source bounds of the clicked icon
526 * @param opts Options to pass to startActivity
527 */
Kenny Guyf939dba2014-08-15 15:32:34 +0100528 public void startAppDetailsActivity(ComponentName component, UserHandle user,
Kenny Guy466d2032014-07-23 12:23:35 +0100529 Rect sourceBounds, Bundle opts) {
Makoto Onukide3c16c2017-01-26 11:39:31 -0800530 logErrorForInvalidProfileAccess(user);
Kenny Guy466d2032014-07-23 12:23:35 +0100531 try {
Makoto Onuki3a2541e2017-01-24 09:00:15 -0800532 mService.showAppDetailsAsUser(mContext.getPackageName(),
533 component, sourceBounds, opts, user);
Kenny Guy466d2032014-07-23 12:23:35 +0100534 } catch (RemoteException re) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700535 throw re.rethrowFromSystemServer();
Kenny Guy466d2032014-07-23 12:23:35 +0100536 }
537 }
538
539 /**
Sunny Goyala6be88a2017-01-12 16:27:58 -0800540 * Retrieves a list of config activities for creating {@link ShortcutInfo}.
541 *
542 * @param packageName The specific package to query. If null, it checks all installed packages
543 * in the profile.
544 * @param user The UserHandle of the profile.
545 * @return List of config activities. Can be an empty list but will not be null.
546 *
547 * @see Intent#ACTION_CREATE_SHORTCUT
548 * @see #getShortcutConfigActivityIntent(LauncherActivityInfo)
549 */
550 public List<LauncherActivityInfo> getShortcutConfigActivityList(@Nullable String packageName,
551 @NonNull UserHandle user) {
Makoto Onukide3c16c2017-01-26 11:39:31 -0800552 logErrorForInvalidProfileAccess(user);
Sunny Goyala6be88a2017-01-12 16:27:58 -0800553 try {
Makoto Onuki3a2541e2017-01-24 09:00:15 -0800554 return convertToActivityList(mService.getShortcutConfigActivities(
555 mContext.getPackageName(), packageName, user),
Sunny Goyala6be88a2017-01-12 16:27:58 -0800556 user);
557 } catch (RemoteException re) {
558 throw re.rethrowFromSystemServer();
559 }
560 }
561
562 private List<LauncherActivityInfo> convertToActivityList(
563 @Nullable ParceledListSlice<ResolveInfo> activities, UserHandle user) {
564 if (activities == null) {
565 return Collections.EMPTY_LIST;
566 }
567 ArrayList<LauncherActivityInfo> lais = new ArrayList<>();
568 for (ResolveInfo ri : activities.getList()) {
569 LauncherActivityInfo lai = new LauncherActivityInfo(mContext, ri.activityInfo, user);
570 if (DEBUG) {
571 Log.v(TAG, "Returning activity for profile " + user + " : "
572 + lai.getComponentName());
573 }
574 lais.add(lai);
575 }
576 return lais;
577 }
578
579 /**
580 * Returns an intent sender which can be used to start the configure activity for creating
581 * custom shortcuts. Use this method if the provider is in another profile as you are not
582 * allowed to start an activity in another profile.
583 *
584 * <p>The caller should receive {@link PinItemRequest} in onActivityResult on
585 * {@link android.app.Activity#RESULT_OK}.
586 *
587 * <p>Callers must be allowed to access the shortcut information, as defined in {@link
588 * #hasShortcutHostPermission()}.
589 *
590 * @param info a configuration activity returned by {@link #getShortcutConfigActivityList}
591 *
592 * @throws IllegalStateException when the user is locked or not running.
593 * @throws SecurityException if {@link #hasShortcutHostPermission()} is false.
594 *
595 * @see #getPinItemRequest(Intent)
596 * @see Intent#ACTION_CREATE_SHORTCUT
597 * @see android.app.Activity#startIntentSenderForResult
598 */
Makoto Onukide3c16c2017-01-26 11:39:31 -0800599 @Nullable
Sunny Goyala6be88a2017-01-12 16:27:58 -0800600 public IntentSender getShortcutConfigActivityIntent(@NonNull LauncherActivityInfo info) {
601 try {
602 return mService.getShortcutConfigActivityIntent(
603 mContext.getPackageName(), info.getComponentName(), info.getUser());
604 } catch (RemoteException re) {
605 throw re.rethrowFromSystemServer();
606 }
607 }
608
609 /**
Kenny Guy53fa4ec2014-04-29 14:24:18 +0100610 * Checks if the package is installed and enabled for a profile.
611 *
612 * @param packageName The package to check.
613 * @param user The UserHandle of the profile.
614 *
615 * @return true if the package exists and is enabled.
616 */
Kenny Guyf939dba2014-08-15 15:32:34 +0100617 public boolean isPackageEnabled(String packageName, UserHandle user) {
Makoto Onukide3c16c2017-01-26 11:39:31 -0800618 logErrorForInvalidProfileAccess(user);
Kenny Guy53fa4ec2014-04-29 14:24:18 +0100619 try {
Makoto Onuki3a2541e2017-01-24 09:00:15 -0800620 return mService.isPackageEnabled(mContext.getPackageName(), packageName, user);
Kenny Guy53fa4ec2014-04-29 14:24:18 +0100621 } catch (RemoteException re) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700622 throw re.rethrowFromSystemServer();
Kenny Guy53fa4ec2014-04-29 14:24:18 +0100623 }
624 }
625
626 /**
Benjamin Miller7afa84c2017-07-17 13:01:35 +0200627 * Returns {@link ApplicationInfo} about an application installed for a specific user profile.
Kenny Guy77242752016-01-15 13:29:06 +0000628 *
Amith Yamasani0d1fd8d2016-10-12 14:21:51 -0700629 * @param packageName The package name of the application
Kenny Guy77242752016-01-15 13:29:06 +0000630 * @param flags Additional option flags {@link PackageManager#getApplicationInfo}
631 * @param user The UserHandle of the profile.
632 *
Benjamin Miller7afa84c2017-07-17 13:01:35 +0200633 * @return {@link ApplicationInfo} containing information about the package. Returns
634 * {@code null} if the package isn't installed for the given profile, or the profile
635 * isn't enabled.
Kenny Guy77242752016-01-15 13:29:06 +0000636 */
Makoto Onuki7c7fbf62017-04-14 11:03:56 -0700637 public ApplicationInfo getApplicationInfo(@NonNull String packageName,
638 @ApplicationInfoFlags int flags, @NonNull UserHandle user)
639 throws PackageManager.NameNotFoundException {
640 Preconditions.checkNotNull(packageName, "packageName");
641 Preconditions.checkNotNull(packageName, "user");
Makoto Onukide3c16c2017-01-26 11:39:31 -0800642 logErrorForInvalidProfileAccess(user);
Kenny Guy77242752016-01-15 13:29:06 +0000643 try {
Makoto Onuki7c7fbf62017-04-14 11:03:56 -0700644 final ApplicationInfo ai = mService
645 .getApplicationInfo(mContext.getPackageName(), packageName, flags, user);
646 if (ai == null) {
647 throw new NameNotFoundException("Package " + packageName + " not found for user "
648 + user.getIdentifier());
649 }
650 return ai;
Kenny Guy77242752016-01-15 13:29:06 +0000651 } catch (RemoteException re) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700652 throw re.rethrowFromSystemServer();
Kenny Guy77242752016-01-15 13:29:06 +0000653 }
654 }
655
656 /**
Kenny Guy53fa4ec2014-04-29 14:24:18 +0100657 * Checks if the activity exists and it enabled for a profile.
658 *
659 * @param component The activity to check.
660 * @param user The UserHandle of the profile.
661 *
662 * @return true if the activity exists and is enabled.
663 */
Kenny Guyf939dba2014-08-15 15:32:34 +0100664 public boolean isActivityEnabled(ComponentName component, UserHandle user) {
Makoto Onukide3c16c2017-01-26 11:39:31 -0800665 logErrorForInvalidProfileAccess(user);
Kenny Guy53fa4ec2014-04-29 14:24:18 +0100666 try {
Makoto Onuki3a2541e2017-01-24 09:00:15 -0800667 return mService.isActivityEnabled(mContext.getPackageName(), component, user);
Kenny Guy53fa4ec2014-04-29 14:24:18 +0100668 } catch (RemoteException re) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700669 throw re.rethrowFromSystemServer();
Kenny Guy53fa4ec2014-04-29 14:24:18 +0100670 }
671 }
672
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800673 /**
Makoto Onuki2d5b4652016-03-11 16:09:54 -0800674 * Returns whether the caller can access the shortcut information.
675 *
676 * <p>Only the default launcher can access the shortcut information.
677 *
Makoto Onuki4a910962016-07-07 13:57:34 -0700678 * <p>Note when this method returns {@code false}, it may be a temporary situation because
Makoto Onuki2d5b4652016-03-11 16:09:54 -0800679 * the user is trying a new launcher application. The user may decide to change the default
Makoto Onuki4a910962016-07-07 13:57:34 -0700680 * launcher back to the calling application again, so even if a launcher application loses
Makoto Onuki2d5b4652016-03-11 16:09:54 -0800681 * this permission, it does <b>not</b> have to purge pinned shortcut information.
Makoto Onukife9c9662016-07-25 15:12:23 -0700682 * If the calling launcher application contains pinned shortcuts, they will still work,
683 * even though the caller no longer has the shortcut host permission.
Makoto Onuki4a910962016-07-07 13:57:34 -0700684 *
Makoto Onuki02f338e2016-07-29 09:40:40 -0700685 * @throws IllegalStateException when the user is locked.
Makoto Onuki9c850012016-07-26 15:50:50 -0700686 *
Makoto Onuki4a910962016-07-07 13:57:34 -0700687 * @see ShortcutManager
Makoto Onuki2d5b4652016-03-11 16:09:54 -0800688 */
689 public boolean hasShortcutHostPermission() {
690 try {
691 return mService.hasShortcutHostPermission(mContext.getPackageName());
692 } catch (RemoteException re) {
693 throw re.rethrowFromSystemServer();
694 }
695 }
696
Makoto Onukib1588c02017-10-12 15:11:45 -0700697 private List<ShortcutInfo> maybeUpdateDisabledMessage(List<ShortcutInfo> shortcuts) {
698 if (shortcuts == null) {
699 return null;
700 }
701 for (int i = shortcuts.size() - 1; i >= 0; i--) {
702 final ShortcutInfo si = shortcuts.get(i);
703 final String message = ShortcutInfo.getDisabledReasonForRestoreIssue(mContext,
704 si.getDisabledReason());
705 if (message != null) {
706 si.setDisabledMessage(message);
707 }
708 }
709 return shortcuts;
710 }
711
Makoto Onuki2d5b4652016-03-11 16:09:54 -0800712 /**
Makoto Onuki4a910962016-07-07 13:57:34 -0700713 * Returns {@link ShortcutInfo}s that match {@code query}.
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800714 *
Makoto Onuki2d5b4652016-03-11 16:09:54 -0800715 * <p>Callers must be allowed to access the shortcut information, as defined in {@link
716 * #hasShortcutHostPermission()}.
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800717 *
718 * @param query result includes shortcuts matching this query.
719 * @param user The UserHandle of the profile.
720 *
721 * @return the IDs of {@link ShortcutInfo}s that match the query.
Makoto Onuki02f338e2016-07-29 09:40:40 -0700722 * @throws IllegalStateException when the user is locked, or when the {@code user} user
723 * is locked or not running.
Makoto Onuki4a910962016-07-07 13:57:34 -0700724 *
725 * @see ShortcutManager
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800726 */
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800727 @Nullable
728 public List<ShortcutInfo> getShortcuts(@NonNull ShortcutQuery query,
729 @NonNull UserHandle user) {
Makoto Onukide3c16c2017-01-26 11:39:31 -0800730 logErrorForInvalidProfileAccess(user);
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800731 try {
Makoto Onukib1588c02017-10-12 15:11:45 -0700732 // Note this is the only case we need to update the disabled message for shortcuts
733 // that weren't restored.
734 // The restore problem messages are only shown by the user, and publishers will never
735 // see them. The only other API that the launcher gets shortcuts is the shortcut
736 // changed callback, but that only returns shortcuts with the "key" information, so
737 // that won't return disabled message.
738 return maybeUpdateDisabledMessage(mService.getShortcuts(mContext.getPackageName(),
Makoto Onukiabe84422016-04-07 09:41:19 -0700739 query.mChangedSince, query.mPackage, query.mShortcutIds, query.mActivity,
Makoto Onuki99302b52017-03-29 12:42:26 -0700740 query.mQueryFlags, user)
Makoto Onukib1588c02017-10-12 15:11:45 -0700741 .getList());
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800742 } catch (RemoteException e) {
743 throw e.rethrowFromSystemServer();
744 }
745 }
746
747 /**
Makoto Onukiabe84422016-04-07 09:41:19 -0700748 * @hide // No longer used. Use getShortcuts() instead. Kept for unit tests.
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800749 */
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800750 @Nullable
Makoto Onukib5a012f2016-06-21 11:13:53 -0700751 @Deprecated
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800752 public List<ShortcutInfo> getShortcutInfo(@NonNull String packageName,
753 @NonNull List<String> ids, @NonNull UserHandle user) {
Makoto Onukiabe84422016-04-07 09:41:19 -0700754 final ShortcutQuery q = new ShortcutQuery();
755 q.setPackage(packageName);
756 q.setShortcutIds(ids);
Makoto Onuki4d6b87f2016-06-17 13:47:40 -0700757 q.setQueryFlags(ShortcutQuery.FLAG_GET_ALL_KINDS);
Makoto Onukiabe84422016-04-07 09:41:19 -0700758 return getShortcuts(q, user);
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800759 }
760
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800761 /**
762 * Pin shortcuts on a package.
763 *
764 * <p>This API is <b>NOT</b> cumulative; this will replace all pinned shortcuts for the package.
765 * However, different launchers may have different set of pinned shortcuts.
766 *
Makoto Onukife9c9662016-07-25 15:12:23 -0700767 * <p>The calling launcher application must be allowed to access the shortcut information,
768 * as defined in {@link #hasShortcutHostPermission()}.
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800769 *
770 * @param packageName The target package name.
771 * @param shortcutIds The IDs of the shortcut to be pinned.
772 * @param user The UserHandle of the profile.
Makoto Onuki02f338e2016-07-29 09:40:40 -0700773 * @throws IllegalStateException when the user is locked, or when the {@code user} user
774 * is locked or not running.
Makoto Onuki4a910962016-07-07 13:57:34 -0700775 *
776 * @see ShortcutManager
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800777 */
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800778 public void pinShortcuts(@NonNull String packageName, @NonNull List<String> shortcutIds,
779 @NonNull UserHandle user) {
Makoto Onukide3c16c2017-01-26 11:39:31 -0800780 logErrorForInvalidProfileAccess(user);
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800781 try {
782 mService.pinShortcuts(mContext.getPackageName(), packageName, shortcutIds, user);
783 } catch (RemoteException e) {
784 throw e.rethrowFromSystemServer();
785 }
786 }
787
788 /**
Makoto Onukib6d35232016-04-04 15:57:17 -0700789 * @hide kept for testing.
Makoto Onukiabe84422016-04-07 09:41:19 -0700790 */
Makoto Onukib5a012f2016-06-21 11:13:53 -0700791 @Deprecated
Makoto Onukiabe84422016-04-07 09:41:19 -0700792 public int getShortcutIconResId(@NonNull ShortcutInfo shortcut) {
Makoto Onukib6d35232016-04-04 15:57:17 -0700793 return shortcut.getIconResourceId();
Makoto Onukiabe84422016-04-07 09:41:19 -0700794 }
795
796 /**
Makoto Onukib6d35232016-04-04 15:57:17 -0700797 * @hide kept for testing.
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800798 */
Makoto Onukib5a012f2016-06-21 11:13:53 -0700799 @Deprecated
Makoto Onukiabe84422016-04-07 09:41:19 -0700800 public int getShortcutIconResId(@NonNull String packageName, @NonNull String shortcutId,
801 @NonNull UserHandle user) {
Makoto Onukib6d35232016-04-04 15:57:17 -0700802 final ShortcutQuery q = new ShortcutQuery();
803 q.setPackage(packageName);
804 q.setShortcutIds(Arrays.asList(shortcutId));
Makoto Onuki4d6b87f2016-06-17 13:47:40 -0700805 q.setQueryFlags(ShortcutQuery.FLAG_GET_ALL_KINDS);
Makoto Onukib6d35232016-04-04 15:57:17 -0700806 final List<ShortcutInfo> shortcuts = getShortcuts(q, user);
Makoto Onukiabe84422016-04-07 09:41:19 -0700807
Makoto Onukib6d35232016-04-04 15:57:17 -0700808 return shortcuts.size() > 0 ? shortcuts.get(0).getIconResourceId() : 0;
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800809 }
810
811 /**
Makoto Onukib5a012f2016-06-21 11:13:53 -0700812 * @hide internal/unit tests only
Makoto Onukiabe84422016-04-07 09:41:19 -0700813 */
814 public ParcelFileDescriptor getShortcutIconFd(
815 @NonNull ShortcutInfo shortcut) {
Makoto Onuki22fcc682016-05-17 14:52:19 -0700816 return getShortcutIconFd(shortcut.getPackage(), shortcut.getId(),
Makoto Onukiabe84422016-04-07 09:41:19 -0700817 shortcut.getUserId());
818 }
819
820 /**
Makoto Onukib5a012f2016-06-21 11:13:53 -0700821 * @hide internal/unit tests only
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800822 */
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800823 public ParcelFileDescriptor getShortcutIconFd(
Makoto Onukiabe84422016-04-07 09:41:19 -0700824 @NonNull String packageName, @NonNull String shortcutId, @NonNull UserHandle user) {
825 return getShortcutIconFd(packageName, shortcutId, user.getIdentifier());
826 }
827
828 private ParcelFileDescriptor getShortcutIconFd(
829 @NonNull String packageName, @NonNull String shortcutId, int userId) {
Makoto Onuki55046222016-03-08 10:49:47 -0800830 try {
Makoto Onukiabe84422016-04-07 09:41:19 -0700831 return mService.getShortcutIconFd(mContext.getPackageName(),
832 packageName, shortcutId, userId);
Makoto Onuki55046222016-03-08 10:49:47 -0800833 } catch (RemoteException e) {
834 throw e.rethrowFromSystemServer();
835 }
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800836 }
837
Makoto Onuki04b9aab2016-05-23 17:13:30 -0700838 /**
839 * Returns the icon for this shortcut, without any badging for the profile.
840 *
Makoto Onukife9c9662016-07-25 15:12:23 -0700841 * <p>The calling launcher application must be allowed to access the shortcut information,
842 * as defined in {@link #hasShortcutHostPermission()}.
Makoto Onuki4a910962016-07-07 13:57:34 -0700843 *
Makoto Onuki04b9aab2016-05-23 17:13:30 -0700844 * @param density The preferred density of the icon, zero for default density. Use
845 * density DPI values from {@link DisplayMetrics}.
Makoto Onuki4a910962016-07-07 13:57:34 -0700846 *
847 * @return The drawable associated with the shortcut.
Makoto Onuki02f338e2016-07-29 09:40:40 -0700848 * @throws IllegalStateException when the user is locked, or when the {@code user} user
849 * is locked or not running.
Makoto Onuki4a910962016-07-07 13:57:34 -0700850 *
851 * @see ShortcutManager
Makoto Onuki04b9aab2016-05-23 17:13:30 -0700852 * @see #getShortcutBadgedIconDrawable(ShortcutInfo, int)
853 * @see DisplayMetrics
Makoto Onuki04b9aab2016-05-23 17:13:30 -0700854 */
855 public Drawable getShortcutIconDrawable(@NonNull ShortcutInfo shortcut, int density) {
856 if (shortcut.hasIconFile()) {
857 final ParcelFileDescriptor pfd = getShortcutIconFd(shortcut);
858 if (pfd == null) {
859 return null;
860 }
861 try {
862 final Bitmap bmp = BitmapFactory.decodeFileDescriptor(pfd.getFileDescriptor());
Hyunyoung Songf281e7a2017-02-13 10:57:42 -0800863 if (bmp != null) {
864 BitmapDrawable dr = new BitmapDrawable(mContext.getResources(), bmp);
Hyunyoung Songe4179e22017-03-01 12:51:26 -0800865 if (shortcut.hasAdaptiveBitmap()) {
Hyunyoung Songbe8835e2017-02-17 11:25:08 -0800866 return new AdaptiveIconDrawable(null, dr);
Hyunyoung Songf281e7a2017-02-13 10:57:42 -0800867 } else {
868 return dr;
869 }
870 }
871 return null;
Makoto Onuki04b9aab2016-05-23 17:13:30 -0700872 } finally {
873 try {
874 pfd.close();
875 } catch (IOException ignore) {
876 }
877 }
878 } else if (shortcut.hasIconResource()) {
Makoto Onuki2d895c32016-12-02 15:48:40 -0800879 return loadDrawableResourceFromPackage(shortcut.getPackage(),
880 shortcut.getIconResourceId(), shortcut.getUserHandle(), density);
881 } else if (shortcut.getIcon() != null) {
882 // This happens if a shortcut is pending-approval.
883 final Icon icon = shortcut.getIcon();
884 switch (icon.getType()) {
885 case Icon.TYPE_RESOURCE: {
886 return loadDrawableResourceFromPackage(shortcut.getPackage(),
887 icon.getResId(), shortcut.getUserHandle(), density);
Makoto Onuki04b9aab2016-05-23 17:13:30 -0700888 }
Hyunyoung Songf281e7a2017-02-13 10:57:42 -0800889 case Icon.TYPE_BITMAP:
Hyunyoung Songe4179e22017-03-01 12:51:26 -0800890 case Icon.TYPE_ADAPTIVE_BITMAP: {
Makoto Onuki2d895c32016-12-02 15:48:40 -0800891 return icon.loadDrawable(mContext);
892 }
893 default:
894 return null; // Shouldn't happen though.
Makoto Onuki04b9aab2016-05-23 17:13:30 -0700895 }
896 } else {
897 return null; // Has no icon.
898 }
Makoto Onuki20c95f82016-05-11 16:51:01 -0700899 }
900
Makoto Onuki2d895c32016-12-02 15:48:40 -0800901 private Drawable loadDrawableResourceFromPackage(String packageName, int resId,
902 UserHandle user, int density) {
903 try {
904 if (resId == 0) {
905 return null; // Shouldn't happen but just in case.
906 }
907 final ApplicationInfo ai = getApplicationInfo(packageName, /* flags =*/ 0, user);
908 final Resources res = mContext.getPackageManager().getResourcesForApplication(ai);
909 return res.getDrawableForDensity(resId, density);
910 } catch (NameNotFoundException | Resources.NotFoundException e) {
911 return null;
912 }
913 }
914
Makoto Onuki04b9aab2016-05-23 17:13:30 -0700915 /**
916 * Returns the shortcut icon with badging appropriate for the profile.
917 *
Makoto Onukife9c9662016-07-25 15:12:23 -0700918 * <p>The calling launcher application must be allowed to access the shortcut information,
919 * as defined in {@link #hasShortcutHostPermission()}.
Makoto Onuki4a910962016-07-07 13:57:34 -0700920 *
Makoto Onuki04b9aab2016-05-23 17:13:30 -0700921 * @param density Optional density for the icon, or 0 to use the default density. Use
Makoto Onuki04b9aab2016-05-23 17:13:30 -0700922 * @return A badged icon for the shortcut.
Makoto Onuki02f338e2016-07-29 09:40:40 -0700923 * @throws IllegalStateException when the user is locked, or when the {@code user} user
924 * is locked or not running.
Makoto Onuki4a910962016-07-07 13:57:34 -0700925 *
926 * @see ShortcutManager
Makoto Onukife9c9662016-07-25 15:12:23 -0700927 * @see #getShortcutIconDrawable(ShortcutInfo, int)
Makoto Onuki4a910962016-07-07 13:57:34 -0700928 * @see DisplayMetrics
Makoto Onuki04b9aab2016-05-23 17:13:30 -0700929 */
930 public Drawable getShortcutBadgedIconDrawable(ShortcutInfo shortcut, int density) {
931 final Drawable originalIcon = getShortcutIconDrawable(shortcut, density);
932
933 return (originalIcon == null) ? null : mContext.getPackageManager().getUserBadgedIcon(
934 originalIcon, shortcut.getUserHandle());
Makoto Onuki20c95f82016-05-11 16:51:01 -0700935 }
936
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800937 /**
Makoto Onuki4a910962016-07-07 13:57:34 -0700938 * Starts a shortcut.
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800939 *
Makoto Onukife9c9662016-07-25 15:12:23 -0700940 * <p>The calling launcher application must be allowed to access the shortcut information,
941 * as defined in {@link #hasShortcutHostPermission()}.
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800942 *
Makoto Onuki43204b82016-03-08 16:16:44 -0800943 * @param packageName The target shortcut package name.
944 * @param shortcutId The target shortcut ID.
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800945 * @param sourceBounds The Rect containing the source bounds of the clicked icon.
946 * @param startActivityOptions Options to pass to startActivity.
947 * @param user The UserHandle of the profile.
Makoto Onuki02f338e2016-07-29 09:40:40 -0700948 * @throws IllegalStateException when the user is locked, or when the {@code user} user
949 * is locked or not running.
Makoto Onuki83f6d2d2016-07-11 14:30:19 -0700950 *
951 * @throws android.content.ActivityNotFoundException failed to start shortcut. (e.g.
952 * the shortcut no longer exists, is disabled, the intent receiver activity doesn't exist, etc)
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800953 */
Makoto Onukid6880792016-06-29 13:37:43 -0700954 public void startShortcut(@NonNull String packageName, @NonNull String shortcutId,
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800955 @Nullable Rect sourceBounds, @Nullable Bundle startActivityOptions,
956 @NonNull UserHandle user) {
Makoto Onukide3c16c2017-01-26 11:39:31 -0800957 logErrorForInvalidProfileAccess(user);
958
Makoto Onukid6880792016-06-29 13:37:43 -0700959 startShortcut(packageName, shortcutId, sourceBounds, startActivityOptions,
Makoto Onukiabe84422016-04-07 09:41:19 -0700960 user.getIdentifier());
961 }
962
963 /**
964 * Launches a shortcut.
965 *
Makoto Onukife9c9662016-07-25 15:12:23 -0700966 * <p>The calling launcher application must be allowed to access the shortcut information,
967 * as defined in {@link #hasShortcutHostPermission()}.
Makoto Onukiabe84422016-04-07 09:41:19 -0700968 *
969 * @param shortcut The target shortcut.
970 * @param sourceBounds The Rect containing the source bounds of the clicked icon.
971 * @param startActivityOptions Options to pass to startActivity.
Makoto Onuki02f338e2016-07-29 09:40:40 -0700972 * @throws IllegalStateException when the user is locked, or when the {@code user} user
973 * is locked or not running.
Makoto Onuki83f6d2d2016-07-11 14:30:19 -0700974 *
975 * @throws android.content.ActivityNotFoundException failed to start shortcut. (e.g.
976 * the shortcut no longer exists, is disabled, the intent receiver activity doesn't exist, etc)
Makoto Onukiabe84422016-04-07 09:41:19 -0700977 */
Makoto Onukid6880792016-06-29 13:37:43 -0700978 public void startShortcut(@NonNull ShortcutInfo shortcut,
Makoto Onukiabe84422016-04-07 09:41:19 -0700979 @Nullable Rect sourceBounds, @Nullable Bundle startActivityOptions) {
Makoto Onukid6880792016-06-29 13:37:43 -0700980 startShortcut(shortcut.getPackage(), shortcut.getId(),
Makoto Onukiabe84422016-04-07 09:41:19 -0700981 sourceBounds, startActivityOptions,
982 shortcut.getUserId());
983 }
984
Makoto Onukid6880792016-06-29 13:37:43 -0700985 private void startShortcut(@NonNull String packageName, @NonNull String shortcutId,
Makoto Onukiabe84422016-04-07 09:41:19 -0700986 @Nullable Rect sourceBounds, @Nullable Bundle startActivityOptions,
987 int userId) {
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800988 try {
Makoto Onuki83f6d2d2016-07-11 14:30:19 -0700989 final boolean success =
990 mService.startShortcut(mContext.getPackageName(), packageName, shortcutId,
Makoto Onukiabe84422016-04-07 09:41:19 -0700991 sourceBounds, startActivityOptions, userId);
Makoto Onuki83f6d2d2016-07-11 14:30:19 -0700992 if (!success) {
993 throw new ActivityNotFoundException("Shortcut could not be started");
994 }
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800995 } catch (RemoteException e) {
996 throw e.rethrowFromSystemServer();
997 }
998 }
Kenny Guy53fa4ec2014-04-29 14:24:18 +0100999
1000 /**
Kenny Guy10a574f2014-08-26 16:17:58 +01001001 * Registers a callback for changes to packages in current and managed profiles.
Kenny Guyc01545372014-06-16 14:17:26 +01001002 *
Kenny Guy10a574f2014-08-26 16:17:58 +01001003 * @param callback The callback to register.
Kenny Guyc01545372014-06-16 14:17:26 +01001004 */
Kenny Guy10a574f2014-08-26 16:17:58 +01001005 public void registerCallback(Callback callback) {
1006 registerCallback(callback, null);
Kenny Guyb42c89b2014-07-28 19:20:07 +01001007 }
1008
1009 /**
Kenny Guy10a574f2014-08-26 16:17:58 +01001010 * Registers a callback for changes to packages in current and managed profiles.
Kenny Guyb42c89b2014-07-28 19:20:07 +01001011 *
Kenny Guy10a574f2014-08-26 16:17:58 +01001012 * @param callback The callback to register.
Kenny Guyb42c89b2014-07-28 19:20:07 +01001013 * @param handler that should be used to post callbacks on, may be null.
1014 */
Kenny Guy10a574f2014-08-26 16:17:58 +01001015 public void registerCallback(Callback callback, Handler handler) {
Kenny Guyc01545372014-06-16 14:17:26 +01001016 synchronized (this) {
Kenny Guy172a2162015-06-19 17:21:28 +01001017 if (callback != null && findCallbackLocked(callback) < 0) {
Kenny Guyb42c89b2014-07-28 19:20:07 +01001018 boolean addedFirstCallback = mCallbacks.size() == 0;
1019 addCallbackLocked(callback, handler);
1020 if (addedFirstCallback) {
Kenny Guyc01545372014-06-16 14:17:26 +01001021 try {
Makoto Onuki4dbe0de2016-03-14 17:31:49 -07001022 mService.addOnAppsChangedListener(mContext.getPackageName(),
1023 mAppsChangedListener);
Kenny Guyc01545372014-06-16 14:17:26 +01001024 } catch (RemoteException re) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001025 throw re.rethrowFromSystemServer();
Kenny Guyc01545372014-06-16 14:17:26 +01001026 }
1027 }
1028 }
1029 }
1030 }
1031
1032 /**
Kenny Guy10a574f2014-08-26 16:17:58 +01001033 * Unregisters a callback that was previously registered.
Kenny Guyc01545372014-06-16 14:17:26 +01001034 *
Kenny Guy10a574f2014-08-26 16:17:58 +01001035 * @param callback The callback to unregister.
1036 * @see #registerCallback(Callback)
Kenny Guyc01545372014-06-16 14:17:26 +01001037 */
Kenny Guy10a574f2014-08-26 16:17:58 +01001038 public void unregisterCallback(Callback callback) {
Kenny Guyc01545372014-06-16 14:17:26 +01001039 synchronized (this) {
Kenny Guyb42c89b2014-07-28 19:20:07 +01001040 removeCallbackLocked(callback);
Kenny Guy44b6dee2014-07-10 18:10:14 +01001041 if (mCallbacks.size() == 0) {
Amith Yamasanie781c812014-05-28 15:28:18 -07001042 try {
1043 mService.removeOnAppsChangedListener(mAppsChangedListener);
1044 } catch (RemoteException re) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001045 throw re.rethrowFromSystemServer();
Amith Yamasanie781c812014-05-28 15:28:18 -07001046 }
Amith Yamasani4f582632014-02-19 14:31:52 -08001047 }
1048 }
1049 }
1050
Kenny Guy172a2162015-06-19 17:21:28 +01001051 /** @return position in mCallbacks for callback or -1 if not present. */
1052 private int findCallbackLocked(Callback callback) {
Kenny Guyb42c89b2014-07-28 19:20:07 +01001053 if (callback == null) {
1054 throw new IllegalArgumentException("Callback cannot be null");
1055 }
1056 final int size = mCallbacks.size();
1057 for (int i = 0; i < size; ++i) {
1058 if (mCallbacks.get(i).mCallback == callback) {
Kenny Guy172a2162015-06-19 17:21:28 +01001059 return i;
Kenny Guyb42c89b2014-07-28 19:20:07 +01001060 }
1061 }
Kenny Guy172a2162015-06-19 17:21:28 +01001062 return -1;
1063 }
1064
1065 private void removeCallbackLocked(Callback callback) {
1066 int pos = findCallbackLocked(callback);
1067 if (pos >= 0) {
1068 mCallbacks.remove(pos);
1069 }
Kenny Guyb42c89b2014-07-28 19:20:07 +01001070 }
1071
Kenny Guyf939dba2014-08-15 15:32:34 +01001072 private void addCallbackLocked(Callback callback, Handler handler) {
Kenny Guyb42c89b2014-07-28 19:20:07 +01001073 // Remove if already present.
1074 removeCallbackLocked(callback);
1075 if (handler == null) {
1076 handler = new Handler();
1077 }
1078 CallbackMessageHandler toAdd = new CallbackMessageHandler(handler.getLooper(), callback);
1079 mCallbacks.add(toAdd);
1080 }
1081
Amith Yamasani4f582632014-02-19 14:31:52 -08001082 private IOnAppsChangedListener.Stub mAppsChangedListener = new IOnAppsChangedListener.Stub() {
1083
1084 @Override
Kenny Guyb42c89b2014-07-28 19:20:07 +01001085 public void onPackageRemoved(UserHandle user, String packageName)
1086 throws RemoteException {
Amith Yamasani4f582632014-02-19 14:31:52 -08001087 if (DEBUG) {
1088 Log.d(TAG, "onPackageRemoved " + user.getIdentifier() + "," + packageName);
1089 }
1090 synchronized (LauncherApps.this) {
Kenny Guyb42c89b2014-07-28 19:20:07 +01001091 for (CallbackMessageHandler callback : mCallbacks) {
1092 callback.postOnPackageRemoved(packageName, user);
Kenny Guyc01545372014-06-16 14:17:26 +01001093 }
Amith Yamasani4f582632014-02-19 14:31:52 -08001094 }
1095 }
1096
1097 @Override
1098 public void onPackageChanged(UserHandle user, String packageName) throws RemoteException {
1099 if (DEBUG) {
1100 Log.d(TAG, "onPackageChanged " + user.getIdentifier() + "," + packageName);
1101 }
1102 synchronized (LauncherApps.this) {
Kenny Guyb42c89b2014-07-28 19:20:07 +01001103 for (CallbackMessageHandler callback : mCallbacks) {
1104 callback.postOnPackageChanged(packageName, user);
Kenny Guyc01545372014-06-16 14:17:26 +01001105 }
Amith Yamasani4f582632014-02-19 14:31:52 -08001106 }
1107 }
1108
1109 @Override
1110 public void onPackageAdded(UserHandle user, String packageName) throws RemoteException {
1111 if (DEBUG) {
1112 Log.d(TAG, "onPackageAdded " + user.getIdentifier() + "," + packageName);
1113 }
1114 synchronized (LauncherApps.this) {
Kenny Guyb42c89b2014-07-28 19:20:07 +01001115 for (CallbackMessageHandler callback : mCallbacks) {
1116 callback.postOnPackageAdded(packageName, user);
Kenny Guyc01545372014-06-16 14:17:26 +01001117 }
Amith Yamasani4f582632014-02-19 14:31:52 -08001118 }
1119 }
1120
1121 @Override
1122 public void onPackagesAvailable(UserHandle user, String[] packageNames, boolean replacing)
1123 throws RemoteException {
1124 if (DEBUG) {
1125 Log.d(TAG, "onPackagesAvailable " + user.getIdentifier() + "," + packageNames);
1126 }
1127 synchronized (LauncherApps.this) {
Kenny Guyb42c89b2014-07-28 19:20:07 +01001128 for (CallbackMessageHandler callback : mCallbacks) {
1129 callback.postOnPackagesAvailable(packageNames, user, replacing);
Kenny Guyc01545372014-06-16 14:17:26 +01001130 }
Amith Yamasani4f582632014-02-19 14:31:52 -08001131 }
1132 }
1133
1134 @Override
1135 public void onPackagesUnavailable(UserHandle user, String[] packageNames, boolean replacing)
1136 throws RemoteException {
1137 if (DEBUG) {
1138 Log.d(TAG, "onPackagesUnavailable " + user.getIdentifier() + "," + packageNames);
1139 }
1140 synchronized (LauncherApps.this) {
Kenny Guyb42c89b2014-07-28 19:20:07 +01001141 for (CallbackMessageHandler callback : mCallbacks) {
1142 callback.postOnPackagesUnavailable(packageNames, user, replacing);
Kenny Guyc01545372014-06-16 14:17:26 +01001143 }
Kenny Guy77242752016-01-15 13:29:06 +00001144 }
1145 }
1146
1147 @Override
1148 public void onPackagesSuspended(UserHandle user, String[] packageNames)
1149 throws RemoteException {
1150 if (DEBUG) {
1151 Log.d(TAG, "onPackagesSuspended " + user.getIdentifier() + "," + packageNames);
1152 }
1153 synchronized (LauncherApps.this) {
1154 for (CallbackMessageHandler callback : mCallbacks) {
1155 callback.postOnPackagesSuspended(packageNames, user);
1156 }
1157 }
1158 }
1159
1160 @Override
1161 public void onPackagesUnsuspended(UserHandle user, String[] packageNames)
1162 throws RemoteException {
1163 if (DEBUG) {
1164 Log.d(TAG, "onPackagesUnsuspended " + user.getIdentifier() + "," + packageNames);
1165 }
1166 synchronized (LauncherApps.this) {
1167 for (CallbackMessageHandler callback : mCallbacks) {
1168 callback.postOnPackagesUnsuspended(packageNames, user);
1169 }
1170 }
Amith Yamasani4f582632014-02-19 14:31:52 -08001171 }
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001172
1173 @Override
1174 public void onShortcutChanged(UserHandle user, String packageName,
1175 ParceledListSlice shortcuts) {
1176 if (DEBUG) {
1177 Log.d(TAG, "onShortcutChanged " + user.getIdentifier() + "," + packageName);
1178 }
1179 final List<ShortcutInfo> list = shortcuts.getList();
1180 synchronized (LauncherApps.this) {
1181 for (CallbackMessageHandler callback : mCallbacks) {
1182 callback.postOnShortcutChanged(packageName, user, list);
1183 }
1184 }
1185 }
Amith Yamasani4f582632014-02-19 14:31:52 -08001186 };
Kenny Guyb42c89b2014-07-28 19:20:07 +01001187
1188 private static class CallbackMessageHandler extends Handler {
1189 private static final int MSG_ADDED = 1;
1190 private static final int MSG_REMOVED = 2;
1191 private static final int MSG_CHANGED = 3;
1192 private static final int MSG_AVAILABLE = 4;
1193 private static final int MSG_UNAVAILABLE = 5;
Kenny Guy77242752016-01-15 13:29:06 +00001194 private static final int MSG_SUSPENDED = 6;
1195 private static final int MSG_UNSUSPENDED = 7;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001196 private static final int MSG_SHORTCUT_CHANGED = 8;
Kenny Guyb42c89b2014-07-28 19:20:07 +01001197
Kenny Guyf939dba2014-08-15 15:32:34 +01001198 private LauncherApps.Callback mCallback;
Kenny Guyb42c89b2014-07-28 19:20:07 +01001199
1200 private static class CallbackInfo {
1201 String[] packageNames;
1202 String packageName;
1203 boolean replacing;
1204 UserHandle user;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001205 List<ShortcutInfo> shortcuts;
Kenny Guyb42c89b2014-07-28 19:20:07 +01001206 }
1207
Kenny Guyf939dba2014-08-15 15:32:34 +01001208 public CallbackMessageHandler(Looper looper, LauncherApps.Callback callback) {
Kenny Guyb42c89b2014-07-28 19:20:07 +01001209 super(looper, null, true);
1210 mCallback = callback;
1211 }
1212
1213 @Override
1214 public void handleMessage(Message msg) {
1215 if (mCallback == null || !(msg.obj instanceof CallbackInfo)) {
1216 return;
1217 }
1218 CallbackInfo info = (CallbackInfo) msg.obj;
1219 switch (msg.what) {
1220 case MSG_ADDED:
1221 mCallback.onPackageAdded(info.packageName, info.user);
1222 break;
1223 case MSG_REMOVED:
1224 mCallback.onPackageRemoved(info.packageName, info.user);
1225 break;
1226 case MSG_CHANGED:
1227 mCallback.onPackageChanged(info.packageName, info.user);
1228 break;
1229 case MSG_AVAILABLE:
1230 mCallback.onPackagesAvailable(info.packageNames, info.user, info.replacing);
1231 break;
1232 case MSG_UNAVAILABLE:
1233 mCallback.onPackagesUnavailable(info.packageNames, info.user, info.replacing);
1234 break;
Kenny Guy77242752016-01-15 13:29:06 +00001235 case MSG_SUSPENDED:
1236 mCallback.onPackagesSuspended(info.packageNames, info.user);
1237 break;
1238 case MSG_UNSUSPENDED:
1239 mCallback.onPackagesUnsuspended(info.packageNames, info.user);
1240 break;
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001241 case MSG_SHORTCUT_CHANGED:
1242 mCallback.onShortcutsChanged(info.packageName, info.shortcuts, info.user);
1243 break;
Kenny Guyb42c89b2014-07-28 19:20:07 +01001244 }
1245 }
1246
1247 public void postOnPackageAdded(String packageName, UserHandle user) {
1248 CallbackInfo info = new CallbackInfo();
1249 info.packageName = packageName;
1250 info.user = user;
1251 obtainMessage(MSG_ADDED, info).sendToTarget();
1252 }
1253
1254 public void postOnPackageRemoved(String packageName, UserHandle user) {
1255 CallbackInfo info = new CallbackInfo();
1256 info.packageName = packageName;
1257 info.user = user;
1258 obtainMessage(MSG_REMOVED, info).sendToTarget();
1259 }
1260
1261 public void postOnPackageChanged(String packageName, UserHandle user) {
1262 CallbackInfo info = new CallbackInfo();
1263 info.packageName = packageName;
1264 info.user = user;
1265 obtainMessage(MSG_CHANGED, info).sendToTarget();
1266 }
1267
1268 public void postOnPackagesAvailable(String[] packageNames, UserHandle user,
1269 boolean replacing) {
1270 CallbackInfo info = new CallbackInfo();
1271 info.packageNames = packageNames;
1272 info.replacing = replacing;
1273 info.user = user;
1274 obtainMessage(MSG_AVAILABLE, info).sendToTarget();
1275 }
1276
1277 public void postOnPackagesUnavailable(String[] packageNames, UserHandle user,
1278 boolean replacing) {
1279 CallbackInfo info = new CallbackInfo();
1280 info.packageNames = packageNames;
1281 info.replacing = replacing;
1282 info.user = user;
1283 obtainMessage(MSG_UNAVAILABLE, info).sendToTarget();
1284 }
Kenny Guy77242752016-01-15 13:29:06 +00001285
1286 public void postOnPackagesSuspended(String[] packageNames, UserHandle user) {
1287 CallbackInfo info = new CallbackInfo();
1288 info.packageNames = packageNames;
1289 info.user = user;
1290 obtainMessage(MSG_SUSPENDED, info).sendToTarget();
1291 }
1292
1293 public void postOnPackagesUnsuspended(String[] packageNames, UserHandle user) {
1294 CallbackInfo info = new CallbackInfo();
1295 info.packageNames = packageNames;
1296 info.user = user;
1297 obtainMessage(MSG_UNSUSPENDED, info).sendToTarget();
1298 }
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001299
1300 public void postOnShortcutChanged(String packageName, UserHandle user,
1301 List<ShortcutInfo> shortcuts) {
1302 CallbackInfo info = new CallbackInfo();
1303 info.packageName = packageName;
1304 info.user = user;
1305 info.shortcuts = shortcuts;
1306 obtainMessage(MSG_SHORTCUT_CHANGED, info).sendToTarget();
1307 }
Kenny Guyb42c89b2014-07-28 19:20:07 +01001308 }
Makoto Onuki2d895c32016-12-02 15:48:40 -08001309
1310 /**
1311 * A helper method to extract a {@link PinItemRequest} set to
1312 * the {@link #EXTRA_PIN_ITEM_REQUEST} extra.
1313 */
1314 public PinItemRequest getPinItemRequest(Intent intent) {
1315 return intent.getParcelableExtra(EXTRA_PIN_ITEM_REQUEST);
1316 }
1317
1318 /**
Sunny Goyal7f7372a2017-01-24 11:53:54 -08001319 * Represents a "pin shortcut" or a "pin appwidget" request made by an app, which is sent with
1320 * an {@link #ACTION_CONFIRM_PIN_SHORTCUT} or {@link #ACTION_CONFIRM_PIN_APPWIDGET} intent
1321 * respectively to the default launcher app.
Makoto Onuki2d895c32016-12-02 15:48:40 -08001322 *
Makoto Onukia37ac3d2017-04-14 12:33:10 -07001323 * <h3>Request of the {@link #REQUEST_TYPE_SHORTCUT} type.
Makoto Onuki0c280712017-01-19 15:14:27 -08001324 *
Makoto Onukia37ac3d2017-04-14 12:33:10 -07001325 * <p>A {@link #REQUEST_TYPE_SHORTCUT} request represents a request to pin a
1326 * {@link ShortcutInfo}. If the launcher accepts a request, call {@link #accept()},
1327 * or {@link #accept(Bundle)} with a null or empty Bundle. No options are defined for
1328 * pin-shortcuts requests.
1329 *
1330 * <p>{@link #getShortcutInfo()} always returns a non-null {@link ShortcutInfo} for this type.
1331 *
1332 * <p>The launcher may receive a request with a {@link ShortcutInfo} that is already pinned, in
1333 * which case {@link ShortcutInfo#isPinned()} returns true. This means the user wants to create
1334 * another pinned shortcut for a shortcut that's already pinned. If the launcher accepts it,
1335 * {@link #accept()} must still be called even though the shortcut is already pinned, and
1336 * create a new pinned shortcut icon for it.
1337 *
1338 * <p>See also {@link ShortcutManager} for more details.
1339 *
1340 * <h3>Request of the {@link #REQUEST_TYPE_APPWIDGET} type.
1341 *
1342 * <p>A {@link #REQUEST_TYPE_SHORTCUT} request represents a request to pin a
1343 * an AppWidget. If the launcher accepts a request, call {@link #accept(Bundle)} with
1344 * the appwidget integer ID set to the
1345 * {@link android.appwidget.AppWidgetManager#EXTRA_APPWIDGET_ID} extra.
1346 *
1347 * <p>{@link #getAppWidgetProviderInfo(Context)} always returns a non-null
1348 * {@link AppWidgetProviderInfo} for this type.
1349 *
1350 * <p>See also {@link AppWidgetManager} for more details.
Sunny Goyal7f7372a2017-01-24 11:53:54 -08001351 *
Makoto Onuki2d895c32016-12-02 15:48:40 -08001352 * @see #EXTRA_PIN_ITEM_REQUEST
1353 * @see #getPinItemRequest(Intent)
1354 */
1355 public static final class PinItemRequest implements Parcelable {
1356
1357 /** This is a request to pin shortcut. */
1358 public static final int REQUEST_TYPE_SHORTCUT = 1;
1359
Sunny Goyal87a563e2017-01-01 19:42:45 -08001360 /** This is a request to pin app widget. */
1361 public static final int REQUEST_TYPE_APPWIDGET = 2;
1362
Makoto Onukif5663b12017-01-09 14:09:56 -08001363 /** @hide */
Makoto Onuki2d895c32016-12-02 15:48:40 -08001364 @IntDef(value = {REQUEST_TYPE_SHORTCUT})
1365 @Retention(RetentionPolicy.SOURCE)
1366 public @interface RequestType {}
1367
1368 private final int mRequestType;
Makoto Onuki2d895c32016-12-02 15:48:40 -08001369 private final IPinItemRequest mInner;
1370
1371 /**
1372 * @hide
1373 */
Makoto Onuki8abba3a2017-02-24 11:34:54 -08001374 public PinItemRequest(IPinItemRequest inner, int type) {
Sunny Goyal87a563e2017-01-01 19:42:45 -08001375 mInner = inner;
Makoto Onuki8abba3a2017-02-24 11:34:54 -08001376 mRequestType = type;
Makoto Onuki2d895c32016-12-02 15:48:40 -08001377 }
1378
1379 /**
Makoto Onukia37ac3d2017-04-14 12:33:10 -07001380 * Represents the type of a request, which is one of the {@code REQUEST_TYPE_} constants.
1381 *
1382 * @return one of the {@code REQUEST_TYPE_} constants.
Makoto Onuki2d895c32016-12-02 15:48:40 -08001383 */
1384 @RequestType
1385 public int getRequestType() {
1386 return mRequestType;
1387 }
1388
1389 /**
Makoto Onukia37ac3d2017-04-14 12:33:10 -07001390 * {@link ShortcutInfo} sent by the requesting app.
1391 * Always non-null for a {@link #REQUEST_TYPE_SHORTCUT} request, and always null for a
1392 * different request type.
1393 *
1394 * @return requested {@link ShortcutInfo} when a request is of the
1395 * {@link #REQUEST_TYPE_SHORTCUT} type. Null otherwise.
Makoto Onuki2d895c32016-12-02 15:48:40 -08001396 */
1397 @Nullable
1398 public ShortcutInfo getShortcutInfo() {
Makoto Onuki8abba3a2017-02-24 11:34:54 -08001399 try {
1400 return mInner.getShortcutInfo();
1401 } catch (RemoteException e) {
1402 throw e.rethrowAsRuntimeException();
1403 }
Makoto Onuki2d895c32016-12-02 15:48:40 -08001404 }
1405
1406 /**
Makoto Onukia37ac3d2017-04-14 12:33:10 -07001407 * {@link AppWidgetProviderInfo} sent by the requesting app.
1408 * Always non-null for a {@link #REQUEST_TYPE_APPWIDGET} request, and always null for a
1409 * different request type.
1410 *
1411 * @return requested {@link AppWidgetProviderInfo} when a request is of the
1412 * {@link #REQUEST_TYPE_APPWIDGET} type. Null otherwise.
Sunny Goyal87a563e2017-01-01 19:42:45 -08001413 */
1414 @Nullable
Sunny Goyal970d4b42017-01-19 15:07:36 -08001415 public AppWidgetProviderInfo getAppWidgetProviderInfo(Context context) {
Makoto Onuki8abba3a2017-02-24 11:34:54 -08001416 try {
1417 final AppWidgetProviderInfo info = mInner.getAppWidgetProviderInfo();
1418 if (info == null) {
1419 return null;
1420 }
Sunny Goyal970d4b42017-01-19 15:07:36 -08001421 info.updateDimensions(context.getResources().getDisplayMetrics());
1422 return info;
Makoto Onuki8abba3a2017-02-24 11:34:54 -08001423 } catch (RemoteException e) {
1424 throw e.rethrowAsRuntimeException();
Sunny Goyal970d4b42017-01-19 15:07:36 -08001425 }
Sunny Goyal87a563e2017-01-01 19:42:45 -08001426 }
1427
1428 /**
Sunny Goyal4ad6b572017-02-28 11:11:51 -08001429 * Any extras sent by the requesting app.
Makoto Onukia37ac3d2017-04-14 12:33:10 -07001430 *
1431 * @return For a shortcut request, this method always return null. For an AppWidget
1432 * request, this method returns the extras passed to the
1433 * {@link android.appwidget.AppWidgetManager#requestPinAppWidget(
1434 * ComponentName, Bundle, PendingIntent)} API. See {@link AppWidgetManager} for details.
Sunny Goyal4ad6b572017-02-28 11:11:51 -08001435 */
1436 @Nullable
1437 public Bundle getExtras() {
1438 try {
1439 return mInner.getExtras();
1440 } catch (RemoteException e) {
1441 throw e.rethrowAsRuntimeException();
1442 }
1443 }
1444
1445 /**
Makoto Onukia37ac3d2017-04-14 12:33:10 -07001446 * Return whether a request is still valid.
1447 *
1448 * @return {@code TRUE} if a request is valid and {@link #accept(Bundle)} may be called.
Makoto Onuki2d895c32016-12-02 15:48:40 -08001449 */
1450 public boolean isValid() {
1451 try {
1452 return mInner.isValid();
1453 } catch (RemoteException e) {
1454 return false;
1455 }
1456 }
1457
1458 /**
1459 * Called by the receiving launcher app when the user accepts the request.
Makoto Onukia37ac3d2017-04-14 12:33:10 -07001460 *
1461 * @param options must be set for a {@link #REQUEST_TYPE_APPWIDGET} request.
1462 *
1463 * @return {@code TRUE} if the shortcut or the AppWidget has actually been pinned.
1464 * {@code FALSE} if the item hasn't been pinned, for example, because the request had
1465 * already been canceled, in which case the launcher must not pin the requested item.
Makoto Onuki2d895c32016-12-02 15:48:40 -08001466 */
1467 public boolean accept(@Nullable Bundle options) {
1468 try {
1469 return mInner.accept(options);
1470 } catch (RemoteException e) {
1471 throw e.rethrowFromSystemServer();
1472 }
1473 }
1474
1475 /**
Makoto Onukia37ac3d2017-04-14 12:33:10 -07001476 * Called by the receiving launcher app when the user accepts the request, with no options.
1477 *
1478 * @return {@code TRUE} if the shortcut or the AppWidget has actually been pinned.
1479 * {@code FALSE} if the item hasn't been pinned, for example, because the request had
1480 * already been canceled, in which case the launcher must not pin the requested item.
Makoto Onuki2d895c32016-12-02 15:48:40 -08001481 */
1482 public boolean accept() {
1483 return accept(/* options= */ null);
1484 }
1485
1486 private PinItemRequest(Parcel source) {
1487 final ClassLoader cl = getClass().getClassLoader();
1488
1489 mRequestType = source.readInt();
Makoto Onuki2d895c32016-12-02 15:48:40 -08001490 mInner = IPinItemRequest.Stub.asInterface(source.readStrongBinder());
1491 }
1492
1493 @Override
1494 public void writeToParcel(Parcel dest, int flags) {
1495 dest.writeInt(mRequestType);
Makoto Onuki2d895c32016-12-02 15:48:40 -08001496 dest.writeStrongBinder(mInner.asBinder());
1497 }
1498
1499 public static final Creator<PinItemRequest> CREATOR =
1500 new Creator<PinItemRequest>() {
1501 public PinItemRequest createFromParcel(Parcel source) {
1502 return new PinItemRequest(source);
1503 }
1504 public PinItemRequest[] newArray(int size) {
1505 return new PinItemRequest[size];
1506 }
1507 };
1508
1509 @Override
1510 public int describeContents() {
1511 return 0;
1512 }
1513 }
Amith Yamasani4f582632014-02-19 14:31:52 -08001514}