当前位置:   article > 正文

Launcher的含义、如何启动的详解_launcher 打开,亮度怎么来的

launcher 打开,亮度怎么来的

当我们手指触摸屏幕上指定App图标Logo的时候,App就由Launcher开始启动了。
Launcher到底是一个概念呢?

Launcher本质上也是一个应用程序,和我们的App一样,也是继承自Activity

packages/apps/Launcher2/src/com/android/launcher2/Launcher.java

 

  1. public final class Launcher extends Activity
  2. implements View.OnClickListener, OnLongClickListener, LauncherModel.Callbacks,
  3. View.OnTouchListener {
  4. }

Launcher类中实现了点击OnClickListener、长按OnLongClickListener等回调接口,来接收用户的输入操作。

 比如,我们点击一个图标,是怎么打来应用呢?
 通过捕捉图标对应的点击事件操作,然后调用startActivity()发送对应的Intent请求,Launcher就是这么做的。

那么到底是处理的哪个对象的点击事件呢?既然Launcher是App,并且有界面,那么肯定有布局文件,是的,我找到了布局文件launcher.xml
 

  1. <FrameLayout
  2. xmlns:android="http://schemas.android.com/apk/res/android"
  3. xmlns:launcher="http://schemas.android.com/apk/res/com.android.launcher"
  4. android:id="@+id/launcher">
  5. <com.android.launcher2.DragLayer
  6. android:id="@+id/drag_layer"
  7. android:layout_width="match_parent"
  8. android:layout_height="match_parent"
  9. android:fitsSystemWindows="true">
  10. <!-- Keep these behind the workspace so that they are not visible when
  11. we go into AllApps -->
  12. //底部操作栏和上面图标布局的分割线
  13. <include
  14. android:id="@+id/dock_divider"
  15. layout="@layout/workspace_divider"
  16. android:layout_marginBottom="@dimen/button_bar_height"
  17. android:layout_gravity="bottom" />
  18. //页面指示器
  19. <include
  20. android:id="@+id/paged_view_indicator"
  21. layout="@layout/scroll_indicator"
  22. android:layout_gravity="bottom"
  23. android:layout_marginBottom="@dimen/button_bar_height" />
  24. <!-- The workspace contains 5 screens of cells -->
  25. //包含了5个屏幕的单元格。类似于手机首页 底部打电话 短信 浏览器 通讯录等底部按钮
  26. <com.android.launcher2.Workspace
  27. android:id="@+id/workspace"
  28. android:layout_width="match_parent"
  29. android:layout_height="match_parent"
  30. android:paddingStart="@dimen/workspace_left_padding"
  31. android:paddingEnd="@dimen/workspace_right_padding"
  32. android:paddingTop="@dimen/workspace_top_padding"
  33. android:paddingBottom="@dimen/workspace_bottom_padding"
  34. launcher:defaultScreen="2"
  35. launcher:cellCountX="@integer/cell_count_x"
  36. launcher:cellCountY="@integer/cell_count_y"
  37. launcher:pageSpacing="@dimen/workspace_page_spacing"
  38. launcher:scrollIndicatorPaddingLeft="@dimen/workspace_divider_padding_left"
  39. launcher:scrollIndicatorPaddingRight="@dimen/workspace_divider_padding_right">
  40. <include android:id="@+id/cell1" layout="@layout/workspace_screen" />
  41. <include android:id="@+id/cell2" layout="@layout/workspace_screen" />
  42. <include android:id="@+id/cell3" layout="@layout/workspace_screen" />
  43. <include android:id="@+id/cell4" layout="@layout/workspace_screen" />
  44. <include android:id="@+id/cell5" layout="@layout/workspace_screen" />
  45. </com.android.launcher2.Workspace>
  46. ...ignore some code...
  47. </com.android.launcher2.DragLayer>
  48. </FrameLayout>

从上面这些我们应该可以看出一些东西来:Launcher大量使用include标签来实现界面的复用,而且定义了很多的自定义控件实现界面效果,dock_divider从布局的参数声明上可以猜出,是底部操作栏和上面图标布局的分割线,而paged_view_indicator则是页面指示器,和App首次进入的引导页下面的界面引导是一样的道理。当然,我们最关心的是Workspace这个布局,因为注释里面说在这里面包含了5个屏幕的单元格,想必你也猜到了,这个就是在首页存放我们图标的那五个界面(不同的ROM会做不同的DIY,数量不固定)。

workspace_screen布局:
 

  1. <com.android.launcher2.CellLayout
  2. xmlns:android="http://schemas.android.com/apk/res/android"
  3. xmlns:launcher="http://schemas.android.com/apk/res/com.android.launcher"
  4. android:layout_width="wrap_content"
  5. android:layout_height="wrap_content"
  6. android:paddingStart="@dimen/cell_layout_left_padding"
  7. android:paddingEnd="@dimen/cell_layout_right_padding"
  8. android:paddingTop="@dimen/cell_layout_top_padding"
  9. android:paddingBottom="@dimen/cell_layout_bottom_padding"
  10. android:hapticFeedbackEnabled="false"
  11. launcher:cellWidth="@dimen/workspace_cell_width"
  12. launcher:cellHeight="@dimen/workspace_cell_height"
  13. launcher:widthGap="@dimen/workspace_width_gap"
  14. launcher:heightGap="@dimen/workspace_height_gap"
  15. launcher:maxGap="@dimen/workspace_max_gap" />

系统界面布局分析:
1.底部快捷入口View:
 就一个CellLayout自定义布局,那么我们就可以猜到了,既然可以存放图标,那么这个自定义的布局很有可能是继承自ViewGroup或者是其子类,实际上,CellLayout确实是继承自ViewGroup。在CellLayout里面,只放了一个子View,那就是ShortcutAndWidgetContainer。从名字也可以看出来,ShortcutAndWidgetContainer这个类就是用来存放快捷图标和Widget小部件的,那么里面放的是什么对象呢?

在桌面上的图标,使用的是BubbleTextView对象,这个对象在TextView的基础之上,添加了一些特效,比如你长按移动图标的时候,图标位置会出现一个背景(不同版本的效果不同),所以我们找到BubbleTextView对象的点击事件,就可以找到Launcher如何开启一个App了。

2.程序列表中的点击:
除了桌面上图标之外,在程序列表中点击图标,也可以开启对应的程序。这里的图标使用的不是BubbleTextView对象,而是PagedViewIcon对象,我们如果找到它的点击事件,就也可以找到Launcher如何开启一个App。


底部快捷的BubbleTextView对象的点击事件在哪里呢?我来告诉你:在Launcher.onClick(View v)里面。
 

  1. /**
  2. * Launches the intent referred by the clicked shortcut
  3. */
  4. public void onClick(View v) {
  5. ...ignore some code...
  6. Object tag = v.getTag();
  7. if (tag instanceof ShortcutInfo) {
  8. // Open shortcut
  9. final Intent intent = ((ShortcutInfo) tag).intent;
  10. int[] pos = new int[2];
  11. v.getLocationOnScreen(pos);
  12. intent.setSourceBounds(new Rect(pos[0], pos[1],
  13. pos[0] + v.getWidth(), pos[1] + v.getHeight()));
  14. //开始开启Activity咯~
  15. boolean success = startActivitySafely(v, intent, tag);
  16. if (success && v instanceof BubbleTextView) {
  17. mWaitingForResume = (BubbleTextView) v;
  18. mWaitingForResume.setStayPressed(true);
  19. }
  20. } else if (tag instanceof FolderInfo) {
  21. //如果点击的是图标文件夹,就打开文件夹
  22. if (v instanceof FolderIcon) {
  23. FolderIcon fi = (FolderIcon) v;
  24. handleFolderClick(fi);
  25. }
  26. } else if (v == mAllAppsButton) {
  27. ...ignore some code...
  28. }
  29. }

程序列表中的点击:
 

程序列表界面使用的是AppsCustomizePagedView对象,所以我在这个类里面找到了onClick(View v)。

com.android.launcher2.AppsCustomizePagedView.java

  1. /**
  2. * The Apps/Customize page that displays all the applications, widgets, and shortcuts.
  3. */
  4. public class AppsCustomizePagedView extends PagedViewWithDraggableItems implements
  5. View.OnClickListener, View.OnKeyListener, DragSource,
  6. PagedViewIcon.PressedCallback, PagedViewWidget.ShortPressListener,
  7. LauncherTransitionable {
  8. @Override
  9. public void onClick(View v) {
  10. ...ignore some code...
  11. if (v instanceof PagedViewIcon) {
  12. mLauncher.updateWallpaperVisibility(true);
  13. mLauncher.startActivitySafely(v, appInfo.intent, appInfo);
  14. } else if (v instanceof PagedViewWidget) {
  15. ...ignore some code..
  16. }
  17. }
  18. }

两种方式,殊途同归!

不管从哪里点击图标,调用的都是Launcher.startActivitySafely()方法。

下面一起来看一下Launcher.startActivitySafely()的流程

  1. boolean startActivitySafely(View v, Intent intent, Object tag) {
  2. boolean success = false;
  3. try {
  4. success = startActivity(v, intent, tag);
  5. } catch (ActivityNotFoundException e) {
  6. Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
  7. Log.e(TAG, "Unable to launch. tag=" + tag + " intent=" + intent, e);
  8. }
  9. return success;
  10. }
  11. boolean startActivity(View v, Intent intent, Object tag) {
  12. //Activity会添加到一个新的Task栈
  13. intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
  14. try {
  15. boolean useLaunchAnimation = (v != null) &&
  16. !intent.hasExtra(INTENT_EXTRA_IGNORE_LAUNCH_ANIMATION);
  17. if (useLaunchAnimation) {
  18. if (user == null || user.equals(android.os.Process.myUserHandle())) {
  19. startActivity(intent, opts.toBundle());
  20. } else {
  21. launcherApps.startMainActivity(intent.getComponent(), user,
  22. intent.getSourceBounds(),
  23. opts.toBundle());
  24. }
  25. } else {
  26. if (user == null || user.equals(android.os.Process.myUserHandle())) {
  27. startActivity(intent);
  28. } else {
  29. launcherApps.startMainActivity(intent.getComponent(), user,
  30. intent.getSourceBounds(), null);
  31. }
  32. }
  33. return true;
  34. } catch (SecurityException e) {
  35. ...
  36. }
  37. return false;
  38. }
  39. //实际调用的是 startActivityForResult方法
  40. @Override
  41. public void startActivity(Intent intent, @Nullable Bundle options) {
  42. if (options != null) {
  43. startActivityForResult(intent, -1, options);
  44. } else {
  45. // Note we want to go through this call for compatibility with
  46. // applications that may have overridden the method.
  47. startActivityForResult(intent, -1);
  48. }
  49. }

所以,Launcher开启一个App,其实和我们在Activity中直接startActivity()基本一样,都是调用Activity.startActivityForResult()

 

本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号