当前位置:   article > 正文

通过Launcher启动应用的过程分析_launcherappsservice

launcherappsservice

通过Launcher启动应用的过程分析

通过Lanucher启动 应用时会调用Lanucher的onClick方法。

  1. Lanucher.java
  2. /**
  3. * Launches the intent referred by the clicked shortcut.
  4. *
  5. * @param v The view representing the clicked shortcut.
  6. */
  7. public void onClick(View v) {
  8. // Make sure that rogue clicks don't get through while allapps is launching, or after the
  9. // view has detached (it's possible for this to happen if the view is removed mid touch).
  10. if (v.getWindowToken() == null) {
  11. return;
  12. }
  13. if (!mWorkspace.isFinishedSwitchingState()) {
  14. return;
  15. }
  16. Object tag = v.getTag();
  17. /*
  18. ShortcutInfo是Lanucher界面上的应用图标,封装了应用的信息吧
  19. */
  20. if (tag instanceof ShortcutInfo) {
  21. // Open shortcut
  22. final Intent intent = ((ShortcutInfo) tag).intent;
  23. /*
  24. 构造了数组保存要点击的应用图标在界面的位置
  25. */
  26. int[] pos = new int[2];
  27. v.getLocationOnScreen(pos);
  28. intent.setSourceBounds(new Rect(pos[0], pos[1],
  29. pos[0] + v.getWidth(), pos[1] + v.getHeight()));
  30. /*
  31. 这一步开始去启动Activity,什么时候能返回呢,应该是调用传递给了系统服务后就可以了
  32. */
  33. boolean success = startActivitySafely(v, intent, tag);
  34. if (success && v instanceof BubbleTextView) {
  35. mWaitingForResume = (BubbleTextView) v;
  36. mWaitingForResume.setStayPressed(true);
  37. }
  38. } else if (tag instanceof FolderInfo) {
  39. if (v instanceof FolderIcon) {
  40. FolderIcon fi = (FolderIcon) v;
  41. handleFolderClick(fi);
  42. }
  43. } else if (v == mAllAppsButton) {
  44. if (isAllAppsVisible()) {
  45. showWorkspace(true);
  46. } else {
  47. onClickAllAppsButton(v);
  48. }
  49. }
  50. }

 

  1. Lanucher.java
  2. boolean startActivitySafely(View v, Intent intent, Object tag) {
  3. boolean success = false;
  4. try {
  5. success = startActivity(v, intent, tag);
  6. } catch (ActivityNotFoundException e) {
  7. Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
  8. Log.e(TAG, "Unable to launch. tag=" + tag + " intent=" + intent, e);
  9. }
  10. return success;
  11. }
  12. boolean startActivity(View v, Intent intent, Object tag) {
  13. //设置FLAG的目的是保证每次都在新的Task中启动应用,每一个应用都有自己的task
  14. intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
  15. try {
  16. // Only launch using the new animation if the shortcut has not opted out (this is a
  17. // private contract between launcher and may be ignored in the future).
  18. boolean useLaunchAnimation = (v != null) &&
  19. !intent.hasExtra(INTENT_EXTRA_IGNORE_LAUNCH_ANIMATION);
  20. UserHandle user = (UserHandle) intent.getParcelableExtra(ApplicationInfo.EXTRA_PROFILE);
  21. /*
  22. 该类用于检索当前用户可以启动的所有的Activity的列表以及用户可见的相关的配置文件,Lanucher主要使用该 类,可以通过配置文件查询所有的APP的信息,PackageManager不会为其他的配置文件发送广播,所以如果你想要监听这这些应用包的变化,可以注册监听此PackagerManager的广播Intent.ACTION_MANAGED_PROFILE_ADDED and Intent.ACTION_MANAGED_PROFILE_REMOVED.
  23. */
  24. LauncherApps launcherApps = (LauncherApps)
  25. this.getSystemService(Context.LAUNCHER_APPS_SERVICE);
  26. if (useLaunchAnimation) {
  27. //Activity过度动画相关
  28. ActivityOptions opts = ActivityOptions.makeScaleUpAnimation(v, 0, 0,
  29. v.getMeasuredWidth(), v.getMeasuredHeight());
  30. if (user == null || user.equals(android.os.Process.myUserHandle())) {
  31. // Could be launching some bookkeeping activity
  32. startActivity(intent, opts.toBundle());
  33. } else {
  34. launcherApps.startMainActivity(intent.getComponent(), user,
  35. intent.getSourceBounds(),
  36. opts.toBundle());
  37. }
  38. } else {
  39. //不需要启动动画,下面的判断应该是判断是新启动的应用还是已经有的应用
  40. if (user == null || user.equals(android.os.Process.myUserHandle())) {
  41. //Lanucher继承自Activity所以调用到父类Activity中
  42. startActivity(intent);
  43. } else {
  44. launcherApps.startMainActivity(intent.getComponent(), user,
  45. intent.getSourceBounds(), null);
  46. }
  47. }
  48. return true;
  49. } catch (SecurityException e) {
  50. Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
  51. Log.e(TAG, "Launcher does not have the permission to launch " + intent +
  52. ". Make sure to create a MAIN intent-filter for the corresponding activity " +
  53. "or use the exported attribute for this activity. "
  54. + "tag="+ tag + " intent=" + intent, e);
  55. }
  56. return false;
  57. }

startActivity会调用到Activity的如下代码

  1. Activity.java
  2. @Override
  3. public void startActivity(Intent intent, @Nullable Bundle options) {
  4. //Bundle中保存了之前启动得Activity的信息,如果之前没有Activity则信息为空
  5. if (options != null) {
  6. startActivityForResult(intent, -1, options);
  7. } else {
  8. // Note we want to go through this call for compatibility with
  9. // applications that may have overridden the method.
  10. startActivityForResult(intent, -1);
  11. }
  12. }

launcherApps.startMainActivity,   mService是LanucherAppsService.java

  1. LanucherApps.java
  2. /**
  3. * Starts a Main activity in the specified profile.
  4. *
  5. * @param component The ComponentName of the activity to launch
  6. * @param user The UserHandle of the profile
  7. * @param sourceBounds The Rect containing the source bounds of the clicked icon
  8. * @param opts Options to pass to startActivity
  9. */
  10. public void startMainActivity(ComponentName component, UserHandle user, Rect sourceBounds,
  11. Bundle opts) {
  12. logErrorForInvalidProfileAccess(user);
  13. if (DEBUG) {
  14. Log.i(TAG, "StartMainActivity " + component + " " + user.getIdentifier());
  15. }
  16. try {
  17. mService.startActivityAsUser(mContext.getPackageName(),
  18. component, sourceBounds, opts, user);
  19. } catch (RemoteException re) {
  20. throw re.rethrowFromSystemServer();
  21. }
  22. }
  1. LancherAppsService.java
  2. @Override
  3. public void startActivityAsUser(String callingPackage,
  4. ComponentName component, Rect sourceBounds,
  5. Bundle opts, UserHandle user) throws RemoteException {
  6. if (!canAccessProfile(callingPackage, user, "Cannot start activity")) {
  7. return;
  8. }
  9. if (!isUserEnabled(user)) {
  10. throw new IllegalStateException("Cannot start activity for disabled profile " + user);
  11. }
  12. Intent launchIntent = new Intent(Intent.ACTION_MAIN);
  13. launchIntent.addCategory(Intent.CATEGORY_LAUNCHER);
  14. launchIntent.setSourceBounds(sourceBounds);
  15. launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
  16. | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
  17. launchIntent.setPackage(component.getPackageName());
  18. final int callingUid = injectBinderCallingUid();
  19. long ident = Binder.clearCallingIdentity();
  20. try {
  21. final PackageManagerInternal pmInt =
  22. LocalServices.getService(PackageManagerInternal.class);
  23. ActivityInfo info = pmInt.getActivityInfo(component,
  24. PackageManager.MATCH_DIRECT_BOOT_AWARE
  25. | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
  26. callingUid, user.getIdentifier());
  27. if (!info.exported) {
  28. throw new SecurityException("Cannot launch non-exported components "
  29. + component);
  30. }
  31. // Check that the component actually has Intent.CATEGORY_LAUCNCHER
  32. // as calling startActivityAsUser ignores the category and just
  33. // resolves based on the component if present.
  34. List<ResolveInfo> apps = pmInt.queryIntentActivities(launchIntent,
  35. PackageManager.MATCH_DIRECT_BOOT_AWARE
  36. | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
  37. callingUid, user.getIdentifier());
  38. final int size = apps.size();
  39. /*
  40. 没搞清楚这个for循环在干嘛,for循环的意义在保证系统中存在相应的Activity信息?
  41. */
  42. for (int i = 0; i < size; ++i) {
  43. ActivityInfo activityInfo = apps.get(i).activityInfo;
  44. if (activityInfo.packageName.equals(component.getPackageName()) &&
  45. activityInfo.name.equals(component.getClassName())) {
  46. // Found an activity with category launcher that matches
  47. // this component so ok to launch.
  48. launchIntent.setComponent(component);
  49. mContext.startActivityAsUser(launchIntent, opts, user);
  50. return;
  51. }
  52. }
  53. throw new SecurityException("Attempt to launch activity without "
  54. + " category Intent.CATEGORY_LAUNCHER " + component);
  55. } finally {
  56. Binder.restoreCallingIdentity(ident);
  57. }
  58. }

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小蓝xlanll/article/detail/377124
推荐阅读
相关标签
  

闽ICP备14008679号