赞
踩
通过Launcher启动应用的过程分析
通过Lanucher启动 应用时会调用Lanucher的onClick方法。
- Lanucher.java
- /**
- * Launches the intent referred by the clicked shortcut.
- *
- * @param v The view representing the clicked shortcut.
- */
- public void onClick(View v) {
- // Make sure that rogue clicks don't get through while allapps is launching, or after the
- // view has detached (it's possible for this to happen if the view is removed mid touch).
- if (v.getWindowToken() == null) {
- return;
- }
-
- if (!mWorkspace.isFinishedSwitchingState()) {
- return;
- }
-
- Object tag = v.getTag();
- /*
- ShortcutInfo是Lanucher界面上的应用图标,封装了应用的信息吧
- */
- if (tag instanceof ShortcutInfo) {
- // Open shortcut
- final Intent intent = ((ShortcutInfo) tag).intent;
- /*
- 构造了数组保存要点击的应用图标在界面的位置
- */
- int[] pos = new int[2];
- v.getLocationOnScreen(pos);
- intent.setSourceBounds(new Rect(pos[0], pos[1],
- pos[0] + v.getWidth(), pos[1] + v.getHeight()));
- /*
- 这一步开始去启动Activity,什么时候能返回呢,应该是调用传递给了系统服务后就可以了
- */
- boolean success = startActivitySafely(v, intent, tag);
-
- if (success && v instanceof BubbleTextView) {
- mWaitingForResume = (BubbleTextView) v;
- mWaitingForResume.setStayPressed(true);
- }
- } else if (tag instanceof FolderInfo) {
- if (v instanceof FolderIcon) {
- FolderIcon fi = (FolderIcon) v;
- handleFolderClick(fi);
- }
- } else if (v == mAllAppsButton) {
- if (isAllAppsVisible()) {
- showWorkspace(true);
- } else {
- onClickAllAppsButton(v);
- }
- }
- }
- Lanucher.java
-
- boolean startActivitySafely(View v, Intent intent, Object tag) {
- boolean success = false;
- try {
- success = startActivity(v, intent, tag);
- } catch (ActivityNotFoundException e) {
- Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
- Log.e(TAG, "Unable to launch. tag=" + tag + " intent=" + intent, e);
- }
- return success;
- }
-
-
- boolean startActivity(View v, Intent intent, Object tag) {
- //设置FLAG的目的是保证每次都在新的Task中启动应用,每一个应用都有自己的task
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-
- try {
- // Only launch using the new animation if the shortcut has not opted out (this is a
- // private contract between launcher and may be ignored in the future).
- boolean useLaunchAnimation = (v != null) &&
- !intent.hasExtra(INTENT_EXTRA_IGNORE_LAUNCH_ANIMATION);
- UserHandle user = (UserHandle) intent.getParcelableExtra(ApplicationInfo.EXTRA_PROFILE);
- /*
- 该类用于检索当前用户可以启动的所有的Activity的列表以及用户可见的相关的配置文件,Lanucher主要使用该 类,可以通过配置文件查询所有的APP的信息,PackageManager不会为其他的配置文件发送广播,所以如果你想要监听这这些应用包的变化,可以注册监听此PackagerManager的广播Intent.ACTION_MANAGED_PROFILE_ADDED and Intent.ACTION_MANAGED_PROFILE_REMOVED.
- */
-
- LauncherApps launcherApps = (LauncherApps)
- this.getSystemService(Context.LAUNCHER_APPS_SERVICE);
- if (useLaunchAnimation) {
- //Activity过度动画相关
- ActivityOptions opts = ActivityOptions.makeScaleUpAnimation(v, 0, 0,
- v.getMeasuredWidth(), v.getMeasuredHeight());
- if (user == null || user.equals(android.os.Process.myUserHandle())) {
- // Could be launching some bookkeeping activity
- startActivity(intent, opts.toBundle());
- } else {
- launcherApps.startMainActivity(intent.getComponent(), user,
- intent.getSourceBounds(),
- opts.toBundle());
- }
- } else {
- //不需要启动动画,下面的判断应该是判断是新启动的应用还是已经有的应用
- if (user == null || user.equals(android.os.Process.myUserHandle())) {
- //Lanucher继承自Activity所以调用到父类Activity中
- startActivity(intent);
- } else {
- launcherApps.startMainActivity(intent.getComponent(), user,
- intent.getSourceBounds(), null);
- }
- }
- return true;
- } catch (SecurityException e) {
- Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
- Log.e(TAG, "Launcher does not have the permission to launch " + intent +
- ". Make sure to create a MAIN intent-filter for the corresponding activity " +
- "or use the exported attribute for this activity. "
- + "tag="+ tag + " intent=" + intent, e);
- }
- return false;
- }
startActivity会调用到Activity的如下代码
- Activity.java
- @Override
- public void startActivity(Intent intent, @Nullable Bundle options) {
- //Bundle中保存了之前启动得Activity的信息,如果之前没有Activity则信息为空
- if (options != null) {
- startActivityForResult(intent, -1, options);
- } else {
- // Note we want to go through this call for compatibility with
- // applications that may have overridden the method.
- startActivityForResult(intent, -1);
- }
- }
launcherApps.startMainActivity, mService是LanucherAppsService.java
- LanucherApps.java
- /**
- * Starts a Main activity in the specified profile.
- *
- * @param component The ComponentName of the activity to launch
- * @param user The UserHandle of the profile
- * @param sourceBounds The Rect containing the source bounds of the clicked icon
- * @param opts Options to pass to startActivity
- */
- public void startMainActivity(ComponentName component, UserHandle user, Rect sourceBounds,
- Bundle opts) {
- logErrorForInvalidProfileAccess(user);
- if (DEBUG) {
- Log.i(TAG, "StartMainActivity " + component + " " + user.getIdentifier());
- }
- try {
- mService.startActivityAsUser(mContext.getPackageName(),
- component, sourceBounds, opts, user);
- } catch (RemoteException re) {
- throw re.rethrowFromSystemServer();
- }
- }
- LancherAppsService.java
- @Override
- public void startActivityAsUser(String callingPackage,
- ComponentName component, Rect sourceBounds,
- Bundle opts, UserHandle user) throws RemoteException {
- if (!canAccessProfile(callingPackage, user, "Cannot start activity")) {
- return;
- }
- if (!isUserEnabled(user)) {
- throw new IllegalStateException("Cannot start activity for disabled profile " + user);
- }
-
- Intent launchIntent = new Intent(Intent.ACTION_MAIN);
- launchIntent.addCategory(Intent.CATEGORY_LAUNCHER);
- launchIntent.setSourceBounds(sourceBounds);
- launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
- | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
- launchIntent.setPackage(component.getPackageName());
-
- final int callingUid = injectBinderCallingUid();
- long ident = Binder.clearCallingIdentity();
- try {
- final PackageManagerInternal pmInt =
- LocalServices.getService(PackageManagerInternal.class);
- ActivityInfo info = pmInt.getActivityInfo(component,
- PackageManager.MATCH_DIRECT_BOOT_AWARE
- | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
- callingUid, user.getIdentifier());
- if (!info.exported) {
- throw new SecurityException("Cannot launch non-exported components "
- + component);
- }
-
- // Check that the component actually has Intent.CATEGORY_LAUCNCHER
- // as calling startActivityAsUser ignores the category and just
- // resolves based on the component if present.
- List<ResolveInfo> apps = pmInt.queryIntentActivities(launchIntent,
- PackageManager.MATCH_DIRECT_BOOT_AWARE
- | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
- callingUid, user.getIdentifier());
- final int size = apps.size();
- /*
- 没搞清楚这个for循环在干嘛,for循环的意义在保证系统中存在相应的Activity信息?
- */
- for (int i = 0; i < size; ++i) {
- ActivityInfo activityInfo = apps.get(i).activityInfo;
- if (activityInfo.packageName.equals(component.getPackageName()) &&
- activityInfo.name.equals(component.getClassName())) {
- // Found an activity with category launcher that matches
- // this component so ok to launch.
- launchIntent.setComponent(component);
- mContext.startActivityAsUser(launchIntent, opts, user);
- return;
- }
- }
- throw new SecurityException("Attempt to launch activity without "
- + " category Intent.CATEGORY_LAUNCHER " + component);
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。