LauncherApps.java revision f8880561e67e1da246970b49b14285efd4164ab1
1/* 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 19import android.content.ComponentName; 20import android.content.Context; 21import android.content.Intent; 22import android.content.pm.ILauncherApps; 23import android.content.pm.IOnAppsChangedListener; 24import android.content.pm.PackageManager.ApplicationInfoFlags; 25import android.content.pm.PackageManager.NameNotFoundException; 26import android.graphics.Rect; 27import android.os.Bundle; 28import android.os.Handler; 29import android.os.Looper; 30import android.os.Message; 31import android.os.RemoteException; 32import android.os.UserHandle; 33import android.os.UserManager; 34import android.util.Log; 35 36import java.util.ArrayList; 37import java.util.Collections; 38import java.util.List; 39 40/** 41 * Class for retrieving a list of launchable activities for the current user and any associated 42 * managed profiles. This is mainly for use by launchers. Apps can be queried for each user profile. 43 * Since the PackageManager will not deliver package broadcasts for other profiles, you can register 44 * for package changes here. 45 * <p> 46 * To watch for managed profiles being added or removed, register for the following broadcasts: 47 * {@link Intent#ACTION_MANAGED_PROFILE_ADDED} and {@link Intent#ACTION_MANAGED_PROFILE_REMOVED}. 48 * <p> 49 * You can retrieve the list of profiles associated with this user with 50 * {@link UserManager#getUserProfiles()}. 51 */ 52public class LauncherApps { 53 54 static final String TAG = "LauncherApps"; 55 static final boolean DEBUG = false; 56 57 private Context mContext; 58 private ILauncherApps mService; 59 private PackageManager mPm; 60 61 private List<CallbackMessageHandler> mCallbacks 62 = new ArrayList<CallbackMessageHandler>(); 63 64 /** 65 * Callbacks for package changes to this and related managed profiles. 66 */ 67 public static abstract class Callback { 68 /** 69 * Indicates that a package was removed from the specified profile. 70 * 71 * If a package is removed while being updated onPackageChanged will be 72 * called instead. 73 * 74 * @param packageName The name of the package that was removed. 75 * @param user The UserHandle of the profile that generated the change. 76 */ 77 abstract public void onPackageRemoved(String packageName, UserHandle user); 78 79 /** 80 * Indicates that a package was added to the specified profile. 81 * 82 * If a package is added while being updated then onPackageChanged will be 83 * called instead. 84 * 85 * @param packageName The name of the package that was added. 86 * @param user The UserHandle of the profile that generated the change. 87 */ 88 abstract public void onPackageAdded(String packageName, UserHandle user); 89 90 /** 91 * Indicates that a package was modified in the specified profile. 92 * This can happen, for example, when the package is updated or when 93 * one or more components are enabled or disabled. 94 * 95 * @param packageName The name of the package that has changed. 96 * @param user The UserHandle of the profile that generated the change. 97 */ 98 abstract public void onPackageChanged(String packageName, UserHandle user); 99 100 /** 101 * Indicates that one or more packages have become available. For 102 * example, this can happen when a removable storage card has 103 * reappeared. 104 * 105 * @param packageNames The names of the packages that have become 106 * available. 107 * @param user The UserHandle of the profile that generated the change. 108 * @param replacing Indicates whether these packages are replacing 109 * existing ones. 110 */ 111 abstract public void onPackagesAvailable(String[] packageNames, UserHandle user, 112 boolean replacing); 113 114 /** 115 * Indicates that one or more packages have become unavailable. For 116 * example, this can happen when a removable storage card has been 117 * removed. 118 * 119 * @param packageNames The names of the packages that have become 120 * unavailable. 121 * @param user The UserHandle of the profile that generated the change. 122 * @param replacing Indicates whether the packages are about to be 123 * replaced with new versions. 124 */ 125 abstract public void onPackagesUnavailable(String[] packageNames, UserHandle user, 126 boolean replacing); 127 128 /** 129 * Indicates that one or more packages have been suspended. For 130 * example, this can happen when a Device Administrator suspends 131 * an applicaton. 132 * 133 * @param packageNames The names of the packages that have just been 134 * suspended. 135 * @param user The UserHandle of the profile that generated the change. 136 */ 137 public void onPackagesSuspended(String[] packageNames, UserHandle user) { 138 } 139 140 /** 141 * Indicates that one or more packages have been unsuspended. For 142 * example, this can happen when a Device Administrator unsuspends 143 * an applicaton. 144 * 145 * @param packageNames The names of the packages that have just been 146 * unsuspended. 147 * @param user The UserHandle of the profile that generated the change. 148 */ 149 public void onPackagesUnsuspended(String[] packageNames, UserHandle user) { 150 } 151 } 152 153 /** @hide */ 154 public LauncherApps(Context context, ILauncherApps service) { 155 mContext = context; 156 mService = service; 157 mPm = context.getPackageManager(); 158 } 159 160 /** 161 * Retrieves a list of launchable activities that match {@link Intent#ACTION_MAIN} and 162 * {@link Intent#CATEGORY_LAUNCHER}, for a specified user. 163 * 164 * @param packageName The specific package to query. If null, it checks all installed packages 165 * in the profile. 166 * @param user The UserHandle of the profile. 167 * @return List of launchable activities. Can be an empty list but will not be null. 168 */ 169 public List<LauncherActivityInfo> getActivityList(String packageName, UserHandle user) { 170 ParceledListSlice<ResolveInfo> activities = null; 171 try { 172 activities = mService.getLauncherActivities(packageName, user); 173 } catch (RemoteException re) { 174 throw re.rethrowFromSystemServer(); 175 } 176 if (activities == null) { 177 return Collections.EMPTY_LIST; 178 } 179 ArrayList<LauncherActivityInfo> lais = new ArrayList<LauncherActivityInfo>(); 180 for (ResolveInfo ri : activities.getList()) { 181 LauncherActivityInfo lai = new LauncherActivityInfo(mContext, ri, user); 182 if (DEBUG) { 183 Log.v(TAG, "Returning activity for profile " + user + " : " 184 + lai.getComponentName()); 185 } 186 lais.add(lai); 187 } 188 return lais; 189 } 190 191 static ComponentName getComponentName(ResolveInfo ri) { 192 return new ComponentName(ri.activityInfo.packageName, ri.activityInfo.name); 193 } 194 195 /** 196 * Returns the activity info for a given intent and user handle, if it resolves. Otherwise it 197 * returns null. 198 * 199 * @param intent The intent to find a match for. 200 * @param user The profile to look in for a match. 201 * @return An activity info object if there is a match. 202 */ 203 public LauncherActivityInfo resolveActivity(Intent intent, UserHandle user) { 204 try { 205 ResolveInfo ri = mService.resolveActivity(intent, user); 206 if (ri != null) { 207 LauncherActivityInfo info = new LauncherActivityInfo(mContext, ri, user); 208 return info; 209 } 210 } catch (RemoteException re) { 211 throw re.rethrowFromSystemServer(); 212 } 213 return null; 214 } 215 216 /** 217 * Starts a Main activity in the specified profile. 218 * 219 * @param component The ComponentName of the activity to launch 220 * @param user The UserHandle of the profile 221 * @param sourceBounds The Rect containing the source bounds of the clicked icon 222 * @param opts Options to pass to startActivity 223 */ 224 public void startMainActivity(ComponentName component, UserHandle user, Rect sourceBounds, 225 Bundle opts) { 226 if (DEBUG) { 227 Log.i(TAG, "StartMainActivity " + component + " " + user.getIdentifier()); 228 } 229 try { 230 mService.startActivityAsUser(component, sourceBounds, opts, user); 231 } catch (RemoteException re) { 232 throw re.rethrowFromSystemServer(); 233 } 234 } 235 236 /** 237 * Starts the settings activity to show the application details for a 238 * package in the specified profile. 239 * 240 * @param component The ComponentName of the package to launch settings for. 241 * @param user The UserHandle of the profile 242 * @param sourceBounds The Rect containing the source bounds of the clicked icon 243 * @param opts Options to pass to startActivity 244 */ 245 public void startAppDetailsActivity(ComponentName component, UserHandle user, 246 Rect sourceBounds, Bundle opts) { 247 try { 248 mService.showAppDetailsAsUser(component, sourceBounds, opts, user); 249 } catch (RemoteException re) { 250 throw re.rethrowFromSystemServer(); 251 } 252 } 253 254 /** 255 * Checks if the package is installed and enabled for a profile. 256 * 257 * @param packageName The package to check. 258 * @param user The UserHandle of the profile. 259 * 260 * @return true if the package exists and is enabled. 261 */ 262 public boolean isPackageEnabled(String packageName, UserHandle user) { 263 try { 264 return mService.isPackageEnabled(packageName, user); 265 } catch (RemoteException re) { 266 throw re.rethrowFromSystemServer(); 267 } 268 } 269 270 /** 271 * Retrieve all of the information we know about a particular package / application. 272 * 273 * @param packageName The package of the application 274 * @param flags Additional option flags {@link PackageManager#getApplicationInfo} 275 * @param user The UserHandle of the profile. 276 * 277 * @return An {@link ApplicationInfo} containing information about the package or 278 * null of the package isn't found. 279 */ 280 public ApplicationInfo getApplicationInfo(String packageName, @ApplicationInfoFlags int flags, 281 UserHandle user) { 282 try { 283 return mService.getApplicationInfo(packageName, flags, user); 284 } catch (RemoteException re) { 285 throw re.rethrowFromSystemServer(); 286 } 287 } 288 289 /** 290 * Checks if the activity exists and it enabled for a profile. 291 * 292 * @param component The activity to check. 293 * @param user The UserHandle of the profile. 294 * 295 * @return true if the activity exists and is enabled. 296 */ 297 public boolean isActivityEnabled(ComponentName component, UserHandle user) { 298 try { 299 return mService.isActivityEnabled(component, user); 300 } catch (RemoteException re) { 301 throw re.rethrowFromSystemServer(); 302 } 303 } 304 305 306 /** 307 * Registers a callback for changes to packages in current and managed profiles. 308 * 309 * @param callback The callback to register. 310 */ 311 public void registerCallback(Callback callback) { 312 registerCallback(callback, null); 313 } 314 315 /** 316 * Registers a callback for changes to packages in current and managed profiles. 317 * 318 * @param callback The callback to register. 319 * @param handler that should be used to post callbacks on, may be null. 320 */ 321 public void registerCallback(Callback callback, Handler handler) { 322 synchronized (this) { 323 if (callback != null && findCallbackLocked(callback) < 0) { 324 boolean addedFirstCallback = mCallbacks.size() == 0; 325 addCallbackLocked(callback, handler); 326 if (addedFirstCallback) { 327 try { 328 mService.addOnAppsChangedListener(mAppsChangedListener); 329 } catch (RemoteException re) { 330 throw re.rethrowFromSystemServer(); 331 } 332 } 333 } 334 } 335 } 336 337 /** 338 * Unregisters a callback that was previously registered. 339 * 340 * @param callback The callback to unregister. 341 * @see #registerCallback(Callback) 342 */ 343 public void unregisterCallback(Callback callback) { 344 synchronized (this) { 345 removeCallbackLocked(callback); 346 if (mCallbacks.size() == 0) { 347 try { 348 mService.removeOnAppsChangedListener(mAppsChangedListener); 349 } catch (RemoteException re) { 350 throw re.rethrowFromSystemServer(); 351 } 352 } 353 } 354 } 355 356 /** @return position in mCallbacks for callback or -1 if not present. */ 357 private int findCallbackLocked(Callback callback) { 358 if (callback == null) { 359 throw new IllegalArgumentException("Callback cannot be null"); 360 } 361 final int size = mCallbacks.size(); 362 for (int i = 0; i < size; ++i) { 363 if (mCallbacks.get(i).mCallback == callback) { 364 return i; 365 } 366 } 367 return -1; 368 } 369 370 private void removeCallbackLocked(Callback callback) { 371 int pos = findCallbackLocked(callback); 372 if (pos >= 0) { 373 mCallbacks.remove(pos); 374 } 375 } 376 377 private void addCallbackLocked(Callback callback, Handler handler) { 378 // Remove if already present. 379 removeCallbackLocked(callback); 380 if (handler == null) { 381 handler = new Handler(); 382 } 383 CallbackMessageHandler toAdd = new CallbackMessageHandler(handler.getLooper(), callback); 384 mCallbacks.add(toAdd); 385 } 386 387 private IOnAppsChangedListener.Stub mAppsChangedListener = new IOnAppsChangedListener.Stub() { 388 389 @Override 390 public void onPackageRemoved(UserHandle user, String packageName) 391 throws RemoteException { 392 if (DEBUG) { 393 Log.d(TAG, "onPackageRemoved " + user.getIdentifier() + "," + packageName); 394 } 395 synchronized (LauncherApps.this) { 396 for (CallbackMessageHandler callback : mCallbacks) { 397 callback.postOnPackageRemoved(packageName, user); 398 } 399 } 400 } 401 402 @Override 403 public void onPackageChanged(UserHandle user, String packageName) throws RemoteException { 404 if (DEBUG) { 405 Log.d(TAG, "onPackageChanged " + user.getIdentifier() + "," + packageName); 406 } 407 synchronized (LauncherApps.this) { 408 for (CallbackMessageHandler callback : mCallbacks) { 409 callback.postOnPackageChanged(packageName, user); 410 } 411 } 412 } 413 414 @Override 415 public void onPackageAdded(UserHandle user, String packageName) throws RemoteException { 416 if (DEBUG) { 417 Log.d(TAG, "onPackageAdded " + user.getIdentifier() + "," + packageName); 418 } 419 synchronized (LauncherApps.this) { 420 for (CallbackMessageHandler callback : mCallbacks) { 421 callback.postOnPackageAdded(packageName, user); 422 } 423 } 424 } 425 426 @Override 427 public void onPackagesAvailable(UserHandle user, String[] packageNames, boolean replacing) 428 throws RemoteException { 429 if (DEBUG) { 430 Log.d(TAG, "onPackagesAvailable " + user.getIdentifier() + "," + packageNames); 431 } 432 synchronized (LauncherApps.this) { 433 for (CallbackMessageHandler callback : mCallbacks) { 434 callback.postOnPackagesAvailable(packageNames, user, replacing); 435 } 436 } 437 } 438 439 @Override 440 public void onPackagesUnavailable(UserHandle user, String[] packageNames, boolean replacing) 441 throws RemoteException { 442 if (DEBUG) { 443 Log.d(TAG, "onPackagesUnavailable " + user.getIdentifier() + "," + packageNames); 444 } 445 synchronized (LauncherApps.this) { 446 for (CallbackMessageHandler callback : mCallbacks) { 447 callback.postOnPackagesUnavailable(packageNames, user, replacing); 448 } 449 } 450 } 451 452 @Override 453 public void onPackagesSuspended(UserHandle user, String[] packageNames) 454 throws RemoteException { 455 if (DEBUG) { 456 Log.d(TAG, "onPackagesSuspended " + user.getIdentifier() + "," + packageNames); 457 } 458 synchronized (LauncherApps.this) { 459 for (CallbackMessageHandler callback : mCallbacks) { 460 callback.postOnPackagesSuspended(packageNames, user); 461 } 462 } 463 } 464 465 @Override 466 public void onPackagesUnsuspended(UserHandle user, String[] packageNames) 467 throws RemoteException { 468 if (DEBUG) { 469 Log.d(TAG, "onPackagesUnsuspended " + user.getIdentifier() + "," + packageNames); 470 } 471 synchronized (LauncherApps.this) { 472 for (CallbackMessageHandler callback : mCallbacks) { 473 callback.postOnPackagesUnsuspended(packageNames, user); 474 } 475 } 476 } 477 }; 478 479 private static class CallbackMessageHandler extends Handler { 480 private static final int MSG_ADDED = 1; 481 private static final int MSG_REMOVED = 2; 482 private static final int MSG_CHANGED = 3; 483 private static final int MSG_AVAILABLE = 4; 484 private static final int MSG_UNAVAILABLE = 5; 485 private static final int MSG_SUSPENDED = 6; 486 private static final int MSG_UNSUSPENDED = 7; 487 488 private LauncherApps.Callback mCallback; 489 490 private static class CallbackInfo { 491 String[] packageNames; 492 String packageName; 493 boolean replacing; 494 UserHandle user; 495 } 496 497 public CallbackMessageHandler(Looper looper, LauncherApps.Callback callback) { 498 super(looper, null, true); 499 mCallback = callback; 500 } 501 502 @Override 503 public void handleMessage(Message msg) { 504 if (mCallback == null || !(msg.obj instanceof CallbackInfo)) { 505 return; 506 } 507 CallbackInfo info = (CallbackInfo) msg.obj; 508 switch (msg.what) { 509 case MSG_ADDED: 510 mCallback.onPackageAdded(info.packageName, info.user); 511 break; 512 case MSG_REMOVED: 513 mCallback.onPackageRemoved(info.packageName, info.user); 514 break; 515 case MSG_CHANGED: 516 mCallback.onPackageChanged(info.packageName, info.user); 517 break; 518 case MSG_AVAILABLE: 519 mCallback.onPackagesAvailable(info.packageNames, info.user, info.replacing); 520 break; 521 case MSG_UNAVAILABLE: 522 mCallback.onPackagesUnavailable(info.packageNames, info.user, info.replacing); 523 break; 524 case MSG_SUSPENDED: 525 mCallback.onPackagesSuspended(info.packageNames, info.user); 526 break; 527 case MSG_UNSUSPENDED: 528 mCallback.onPackagesUnsuspended(info.packageNames, info.user); 529 break; 530 } 531 } 532 533 public void postOnPackageAdded(String packageName, UserHandle user) { 534 CallbackInfo info = new CallbackInfo(); 535 info.packageName = packageName; 536 info.user = user; 537 obtainMessage(MSG_ADDED, info).sendToTarget(); 538 } 539 540 public void postOnPackageRemoved(String packageName, UserHandle user) { 541 CallbackInfo info = new CallbackInfo(); 542 info.packageName = packageName; 543 info.user = user; 544 obtainMessage(MSG_REMOVED, info).sendToTarget(); 545 } 546 547 public void postOnPackageChanged(String packageName, UserHandle user) { 548 CallbackInfo info = new CallbackInfo(); 549 info.packageName = packageName; 550 info.user = user; 551 obtainMessage(MSG_CHANGED, info).sendToTarget(); 552 } 553 554 public void postOnPackagesAvailable(String[] packageNames, UserHandle user, 555 boolean replacing) { 556 CallbackInfo info = new CallbackInfo(); 557 info.packageNames = packageNames; 558 info.replacing = replacing; 559 info.user = user; 560 obtainMessage(MSG_AVAILABLE, info).sendToTarget(); 561 } 562 563 public void postOnPackagesUnavailable(String[] packageNames, UserHandle user, 564 boolean replacing) { 565 CallbackInfo info = new CallbackInfo(); 566 info.packageNames = packageNames; 567 info.replacing = replacing; 568 info.user = user; 569 obtainMessage(MSG_UNAVAILABLE, info).sendToTarget(); 570 } 571 572 public void postOnPackagesSuspended(String[] packageNames, UserHandle user) { 573 CallbackInfo info = new CallbackInfo(); 574 info.packageNames = packageNames; 575 info.user = user; 576 obtainMessage(MSG_SUSPENDED, info).sendToTarget(); 577 } 578 579 public void postOnPackagesUnsuspended(String[] packageNames, UserHandle user) { 580 CallbackInfo info = new CallbackInfo(); 581 info.packageNames = packageNames; 582 info.user = user; 583 obtainMessage(MSG_UNSUSPENDED, info).sendToTarget(); 584 } 585 } 586} 587