LauncherApps.java revision c0154537b0b7926ce6a3c778597b3c2735ca5497
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.app.AppGlobals; 20import android.content.ComponentName; 21import android.content.Context; 22import android.content.Intent; 23import android.content.pm.ILauncherApps; 24import android.content.pm.IOnAppsChangedListener; 25import android.content.pm.PackageManager.NameNotFoundException; 26import android.graphics.Rect; 27import android.os.Bundle; 28import android.os.RemoteException; 29import android.os.UserHandle; 30import android.os.UserManager; 31import android.util.Log; 32 33import java.util.ArrayList; 34import java.util.Collections; 35import java.util.List; 36 37/** 38 * Class for retrieving a list of launchable activities for the current user and any associated 39 * managed profiles. This is mainly for use by launchers. Apps can be queried for each user profile. 40 * Since the PackageManager will not deliver package broadcasts for other profiles, you can register 41 * for package changes here. 42 * <p> 43 * To watch for managed profiles being added or removed, register for the following broadcasts: 44 * {@link Intent#ACTION_MANAGED_PROFILE_ADDED} and {@link Intent#ACTION_MANAGED_PROFILE_REMOVED}. 45 * <p> 46 * You can retrieve the list of profiles associated with this user with 47 * {@link UserManager#getUserProfiles()}. 48 */ 49public class LauncherApps { 50 51 static final String TAG = "LauncherApps"; 52 static final boolean DEBUG = false; 53 54 private Context mContext; 55 private ILauncherApps mService; 56 private PackageManager mPm; 57 58 private List<OnAppsChangedListener> mListeners 59 = new ArrayList<OnAppsChangedListener>(); 60 private List<OnAppsChangedCallback> mCallbacks 61 = new ArrayList<OnAppsChangedCallback>(); 62 63 /** 64 * Callbacks for package changes to this and related managed profiles. 65 */ 66 public static abstract class OnAppsChangedCallback { 67 /** 68 * Indicates that a package was removed from the specified profile. 69 * 70 * @param packageName The name of the package that was removed. 71 * @param user The UserHandle of the profile that generated the change. 72 */ 73 abstract public void onPackageRemoved(String packageName, UserHandle user); 74 75 /** 76 * Indicates that a package was added to the specified profile. 77 * 78 * @param packageName The name of the package that was added. 79 * @param user The UserHandle of the profile that generated the change. 80 */ 81 abstract public void onPackageAdded(String packageName, UserHandle user); 82 83 /** 84 * Indicates that a package was modified in the specified profile. 85 * 86 * @param packageName The name of the package that has changed. 87 * @param user The UserHandle of the profile that generated the change. 88 */ 89 abstract public void onPackageChanged(String packageName, UserHandle user); 90 91 /** 92 * Indicates that one or more packages have become available. For 93 * example, this can happen when a removable storage card has 94 * reappeared. 95 * 96 * @param packageNames The names of the packages that have become 97 * available. 98 * @param user The UserHandle of the profile that generated the change. 99 * @param replacing Indicates whether these packages are replacing 100 * existing ones. 101 */ 102 abstract public void onPackagesAvailable(String[] packageNames, UserHandle user, 103 boolean replacing); 104 105 /** 106 * Indicates that one or more packages have become unavailable. For 107 * example, this can happen when a removable storage card has been 108 * removed. 109 * 110 * @param packageNames The names of the packages that have become 111 * unavailable. 112 * @param user The UserHandle of the profile that generated the change. 113 * @param replacing Indicates whether the packages are about to be 114 * replaced with new versions. 115 */ 116 abstract public void onPackagesUnavailable(String[] packageNames, UserHandle user, 117 boolean replacing); 118 } 119 120 /** 121 * Callbacks for package changes to this and related managed profiles. 122 */ 123 public interface OnAppsChangedListener { 124 /** 125 * Indicates that a package was removed from the specified profile. 126 * 127 * @param user The UserHandle of the profile that generated the change. 128 * @param packageName The name of the package that was removed. 129 */ 130 void onPackageRemoved(UserHandle user, String packageName); 131 132 /** 133 * Indicates that a package was added to the specified profile. 134 * 135 * @param user The UserHandle of the profile that generated the change. 136 * @param packageName The name of the package that was added. 137 */ 138 void onPackageAdded(UserHandle user, String packageName); 139 140 /** 141 * Indicates that a package was modified in the specified profile. 142 * 143 * @param user The UserHandle of the profile that generated the change. 144 * @param packageName The name of the package that has changed. 145 */ 146 void onPackageChanged(UserHandle user, String packageName); 147 148 /** 149 * Indicates that one or more packages have become available. For 150 * example, this can happen when a removable storage card has 151 * reappeared. 152 * 153 * @param user The UserHandle of the profile that generated the change. 154 * @param packageNames The names of the packages that have become 155 * available. 156 * @param replacing Indicates whether these packages are replacing 157 * existing ones. 158 */ 159 void onPackagesAvailable(UserHandle user, String[] packageNames, boolean replacing); 160 161 /** 162 * Indicates that one or more packages have become unavailable. For 163 * example, this can happen when a removable storage card has been 164 * removed. 165 * 166 * @param user The UserHandle of the profile that generated the change. 167 * @param packageNames The names of the packages that have become 168 * unavailable. 169 * @param replacing Indicates whether the packages are about to be 170 * replaced with new versions. 171 */ 172 void onPackagesUnavailable(UserHandle user, String[] packageNames, boolean replacing); 173 174 } 175 176 /** @hide */ 177 public LauncherApps(Context context, ILauncherApps service) { 178 mContext = context; 179 mService = service; 180 mPm = context.getPackageManager(); 181 } 182 183 /** 184 * Retrieves a list of launchable activities that match {@link Intent#ACTION_MAIN} and 185 * {@link Intent#CATEGORY_LAUNCHER}, for a specified user. 186 * 187 * @param packageName The specific package to query. If null, it checks all installed packages 188 * in the profile. 189 * @param user The UserHandle of the profile. 190 * @return List of launchable activities. Can be an empty list but will not be null. 191 */ 192 public List<LauncherActivityInfo> getActivityList(String packageName, UserHandle user) { 193 List<ResolveInfo> activities = null; 194 try { 195 activities = mService.getLauncherActivities(packageName, user); 196 } catch (RemoteException re) { 197 } 198 if (activities == null) { 199 return Collections.EMPTY_LIST; 200 } 201 ArrayList<LauncherActivityInfo> lais = new ArrayList<LauncherActivityInfo>(); 202 final int count = activities.size(); 203 for (int i = 0; i < count; i++) { 204 ResolveInfo ri = activities.get(i); 205 long firstInstallTime = 0; 206 try { 207 firstInstallTime = mPm.getPackageInfo(ri.activityInfo.packageName, 208 PackageManager.GET_UNINSTALLED_PACKAGES).firstInstallTime; 209 } catch (NameNotFoundException nnfe) { 210 // Sorry, can't find package 211 } 212 LauncherActivityInfo lai = new LauncherActivityInfo(mContext, ri, user, 213 firstInstallTime); 214 if (DEBUG) { 215 Log.v(TAG, "Returning activity for profile " + user + " : " 216 + lai.getComponentName()); 217 } 218 lais.add(lai); 219 } 220 return lais; 221 } 222 223 static ComponentName getComponentName(ResolveInfo ri) { 224 return new ComponentName(ri.activityInfo.packageName, ri.activityInfo.name); 225 } 226 227 /** 228 * Returns the activity info for a given intent and user handle, if it resolves. Otherwise it 229 * returns null. 230 * 231 * @param intent The intent to find a match for. 232 * @param user The profile to look in for a match. 233 * @return An activity info object if there is a match. 234 */ 235 public LauncherActivityInfo resolveActivity(Intent intent, UserHandle user) { 236 try { 237 ResolveInfo ri = mService.resolveActivity(intent, user); 238 if (ri != null) { 239 long firstInstallTime = 0; 240 try { 241 firstInstallTime = mPm.getPackageInfo(ri.activityInfo.packageName, 242 PackageManager.GET_UNINSTALLED_PACKAGES).firstInstallTime; 243 } catch (NameNotFoundException nnfe) { 244 // Sorry, can't find package 245 } 246 LauncherActivityInfo info = new LauncherActivityInfo(mContext, ri, user, 247 firstInstallTime); 248 return info; 249 } 250 } catch (RemoteException re) { 251 return null; 252 } 253 return null; 254 } 255 256 /** 257 * Starts an activity in the specified profile. 258 * 259 * @param component The ComponentName of the activity to launch 260 * @param sourceBounds The Rect containing the source bounds of the clicked icon 261 * @param opts Options to pass to startActivity 262 * @param user The UserHandle of the profile 263 * @hide remove before ship 264 */ 265 public void startActivityForProfile(ComponentName component, Rect sourceBounds, 266 Bundle opts, UserHandle user) { 267 startActivityForProfile(component, user, sourceBounds, opts); 268 } 269 270 /** 271 * Starts an activity in the specified profile. 272 * 273 * @param component The ComponentName of the activity to launch 274 * @param user The UserHandle of the profile 275 * @param sourceBounds The Rect containing the source bounds of the clicked icon 276 * @param opts Options to pass to startActivity 277 */ 278 public void startActivityForProfile(ComponentName component, UserHandle user, Rect sourceBounds, 279 Bundle opts) { 280 if (DEBUG) { 281 Log.i(TAG, "StartActivityForProfile " + component + " " + user.getIdentifier()); 282 } 283 try { 284 mService.startActivityAsUser(component, sourceBounds, opts, user); 285 } catch (RemoteException re) { 286 // Oops! 287 } 288 } 289 290 /** 291 * Checks if the package is installed and enabled for a profile. 292 * 293 * @param packageName The package to check. 294 * @param user The UserHandle of the profile. 295 * 296 * @return true if the package exists and is enabled. 297 */ 298 public boolean isPackageEnabledForProfile(String packageName, UserHandle user) { 299 try { 300 return mService.isPackageEnabled(packageName, user); 301 } catch (RemoteException re) { 302 return false; 303 } 304 } 305 306 /** 307 * Checks if the activity exists and it enabled for a profile. 308 * 309 * @param component The activity to check. 310 * @param user The UserHandle of the profile. 311 * 312 * @return true if the activity exists and is enabled. 313 */ 314 public boolean isActivityEnabledForProfile(ComponentName component, UserHandle user) { 315 try { 316 return mService.isActivityEnabled(component, user); 317 } catch (RemoteException re) { 318 return false; 319 } 320 } 321 322 323 /** 324 * Adds a listener for changes to packages in current and managed profiles. 325 * 326 * @param listener The listener to add. 327 */ 328 public void addOnAppsChangedListener(OnAppsChangedListener listener) { 329 synchronized (this) { 330 if (listener != null && !mListeners.contains(listener)) { 331 mListeners.add(listener); 332 if (mListeners.size() == 1 && mCallbacks.size() == 0) { 333 try { 334 mService.addOnAppsChangedListener(mAppsChangedListener); 335 } catch (RemoteException re) { 336 } 337 } 338 } 339 } 340 } 341 342 /** 343 * Removes a listener that was previously added. 344 * 345 * @param listener The listener to remove. 346 * @see #addOnAppsChangedListener(OnAppsChangedListener) 347 */ 348 public void removeOnAppsChangedListener(OnAppsChangedListener listener) { 349 synchronized (this) { 350 mListeners.remove(listener); 351 if (mListeners.size() == 0 && mCallbacks.size() == 0) { 352 try { 353 mService.removeOnAppsChangedListener(mAppsChangedListener); 354 } catch (RemoteException re) { 355 } 356 } 357 } 358 } 359 360 /** 361 * Adds a callback for changes to packages in current and managed profiles. 362 * 363 * @param callback The callback to add. 364 */ 365 public void addOnAppsChangedCallback(OnAppsChangedCallback callback) { 366 synchronized (this) { 367 if (callback != null && !mCallbacks.contains(callback)) { 368 mCallbacks.add(callback); 369 if (mCallbacks.size() == 1 && mListeners.size() == 0) { 370 try { 371 mService.addOnAppsChangedListener(mAppsChangedListener); 372 } catch (RemoteException re) { 373 } 374 } 375 } 376 } 377 } 378 379 /** 380 * Removes a callback that was previously added. 381 * 382 * @param callback The callback to remove. 383 * @see #addOnAppsChangedListener(OnAppsChangedCallback) 384 */ 385 public void removeOnAppsChangedCallback(OnAppsChangedCallback callback) { 386 synchronized (this) { 387 mListeners.remove(callback); 388 if (mListeners.size() == 0 && mCallbacks.size() == 0) { 389 try { 390 mService.removeOnAppsChangedListener(mAppsChangedListener); 391 } catch (RemoteException re) { 392 } 393 } 394 } 395 } 396 397 private IOnAppsChangedListener.Stub mAppsChangedListener = new IOnAppsChangedListener.Stub() { 398 399 @Override 400 public void onPackageRemoved(UserHandle user, String packageName) throws RemoteException { 401 if (DEBUG) { 402 Log.d(TAG, "onPackageRemoved " + user.getIdentifier() + "," + packageName); 403 } 404 synchronized (LauncherApps.this) { 405 for (OnAppsChangedListener listener : mListeners) { 406 listener.onPackageRemoved(user, packageName); 407 } 408 for (OnAppsChangedCallback callback : mCallbacks) { 409 callback.onPackageRemoved(packageName, user); 410 } 411 } 412 } 413 414 @Override 415 public void onPackageChanged(UserHandle user, String packageName) throws RemoteException { 416 if (DEBUG) { 417 Log.d(TAG, "onPackageChanged " + user.getIdentifier() + "," + packageName); 418 } 419 synchronized (LauncherApps.this) { 420 for (OnAppsChangedListener listener : mListeners) { 421 listener.onPackageChanged(user, packageName); 422 } 423 for (OnAppsChangedCallback callback : mCallbacks) { 424 callback.onPackageChanged(packageName, user); 425 } 426 } 427 } 428 429 @Override 430 public void onPackageAdded(UserHandle user, String packageName) throws RemoteException { 431 if (DEBUG) { 432 Log.d(TAG, "onPackageAdded " + user.getIdentifier() + "," + packageName); 433 } 434 synchronized (LauncherApps.this) { 435 for (OnAppsChangedListener listener : mListeners) { 436 listener.onPackageAdded(user, packageName); 437 } 438 for (OnAppsChangedCallback callback : mCallbacks) { 439 callback.onPackageAdded(packageName, user); 440 } 441 } 442 } 443 444 @Override 445 public void onPackagesAvailable(UserHandle user, String[] packageNames, boolean replacing) 446 throws RemoteException { 447 if (DEBUG) { 448 Log.d(TAG, "onPackagesAvailable " + user.getIdentifier() + "," + packageNames); 449 } 450 synchronized (LauncherApps.this) { 451 for (OnAppsChangedListener listener : mListeners) { 452 listener.onPackagesAvailable(user, packageNames, replacing); 453 } 454 for (OnAppsChangedCallback callback : mCallbacks) { 455 callback.onPackagesAvailable(packageNames, user, replacing); 456 } 457 } 458 } 459 460 @Override 461 public void onPackagesUnavailable(UserHandle user, String[] packageNames, boolean replacing) 462 throws RemoteException { 463 if (DEBUG) { 464 Log.d(TAG, "onPackagesUnavailable " + user.getIdentifier() + "," + packageNames); 465 } 466 synchronized (LauncherApps.this) { 467 for (OnAppsChangedListener listener : mListeners) { 468 listener.onPackagesUnavailable(user, packageNames, replacing); 469 } 470 for (OnAppsChangedCallback callback : mCallbacks) { 471 callback.onPackagesUnavailable(packageNames, user, replacing); 472 } 473 } 474 } 475 }; 476} 477