博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

Android Launcher分析和修改12——Widget列表信息收集

Posted on 2013-08-14 00:15  泡泡糖  阅读(8543)  评论(1编辑  收藏  举报

  很久没写Launcher分析的文章,最近实在太忙。今天七夕本来是想陪女朋友逛街 ,碰巧打台风呆在家里,就继续写一篇文章。今天主要是讲一下Launcher里面的Widget列表,这方面信息比较多,今天重点讲一下Widget信息收集和Launcher是如何显示Widget。这是这个系列第12篇文章,可是有关Launcher的分析感觉还有很多东西要写。

  Widget列表是Android4.0以后才有的一种新特性,主要是可以直接查看Widget的缩略图,方便用户使用。而且Widget列表放到了AllApp里面,用一个TabHost管理。有关AllApp的TabHost切换,可以参考我前面的文章:AllApp全部应用列表(AppsCustomizeTabHost) 。Widget列表就是在AllApp列表后面。下面是Launcher4.0 的Widget列表:

(PS:新建的QQ群,有兴趣可以加入一起讨论:Android群:322599434)

 

 

1、AppsCustomizePagedView关系

  首先看看Launcher是如何获取系统里面所有的Widget信息,这一部分都在AppsCustomizePagedView类里面,AppsCustomizePagedView类是同时管理显示Widget和所有应用列表。这两者都是这个类负责显示,看名字我们可以看到一个很熟悉的名字PagedView类,这个类前面我已经分析过,是一个十分重要的积累,继承于ViewGroup。主界面的WorkSpace也是继承于PagedView,PagedView主要是实现了页面滑动功能。AppsCustomizePagedView的基类同样是PagedView,下面看看他们的继承关系:

  从上面的继承关系可以看到,AppsCustomizePagedView也是一个GroupView,主要就是用来显示其他view,只是多了页面滑动和拖曳功能。其实这个继承关系跟WorkSpace是基本一样,只是中间的类有点不一样。不了解的朋友,可以看我以前WorkSpace的分析文章。

 

2、Widgets信息收集

下面我们看看AppsCustomizePagedView里面如何统计系统里面Widget的信息。所有的Widget信息会最后保存到一个队列里面:


//Edited by mythou
//http://www.cnblogs.com/mythou/
private ArrayList<Object> mWidgets;  //widget资源

下面我们看看,如何统计收集信息

//Edited by mythou
//http://www.cnblogs.com/mythou/
  public void updatePackages() {
        //清空WIdget列表
        boolean wasEmpty = mWidgets.isEmpty();
        mWidgets.clear();
     //这里获取的是Widget信息 List
<AppWidgetProviderInfo> widgets = AppWidgetManager.getInstance( mLauncher).getInstalledProviders(); Intent shortcutsIntent = new Intent(Intent.ACTION_CREATE_SHORTCUT);
    //获取所有的快捷方式,需要说明的是快捷方式同样显示在Widget里面 List
<ResolveInfo> shortcuts = mPackageManager.queryIntentActivities( shortcutsIntent, 0);
     //遍历所有的Widget插件
for (AppWidgetProviderInfo widget : widgets) {
        //判断插件的最小高宽是否为0,为0不需要显示
if (widget.minWidth > 0 && widget.minHeight > 0) {
          //添加到队列 mWidgets.add(widget); }
else { Log.e(LOG_TAG, "Widget " + widget.provider + " has invalid dimensions (" + widget.minWidth + ", " + widget.minHeight + ")"); } }
     //直接添加所有快捷方式 mWidgets.addAll(shortcuts); Collections.sort(mWidgets,
new LauncherModel.WidgetAndShortcutNameComparator( mPackageManager)); updatePageCounts(); if (wasEmpty) { // The next layout pass will trigger data-ready if both widgets and // apps are set, so request // a layout to do this test and invalidate the page data when ready. if (testDataReady()) requestLayout(); } else { cancelAllTasks(); invalidatePageData(); } }

  上面就是如何获取系统Widget信息的相关代码,主要是通过AppWidgetManager服务获取相关信息。需要注意的是,快捷方式也会显示在Widget列表里面,获取快捷方式的方法,主要是通过Intent的标记识别。通过PackageManager.queryIntentActivities,可以指定过滤所有含有ACTION_CREATE_SHORTCUT标识的程序,这些作为快捷方式也会被添加到Widget队列里面。

 

3、Widget信息初始化

  上面说的是如何获取Widget的相关对象信息,我们可以看到ArrayList里面的类型也是初始化为Object。下面我们看看如何提取Widget里面的信息,然后初始化为View在界面上面显示。

//Edited by mythou
//http://www.cnblogs.com/mythou/
 public void syncWidgetPageItems(final int page, final boolean immediate) {
        int numItemsPerPage = mWidgetCountX * mWidgetCountY;

        //计算Widget相关的长宽和边距,用于后面确定位置
        final ArrayList<Object> items = new ArrayList<Object>();
        int contentWidth = mWidgetSpacingLayout.getContentWidth();
        final int cellWidth = ((contentWidth - mPageLayoutPaddingLeft
                - mPageLayoutPaddingRight - ((mWidgetCountX - 1) * mWidgetWidthGap)) / mWidgetCountX);
        int contentHeight = mWidgetSpacingLayout.getContentHeight();
        final int cellHeight = ((contentHeight - mPageLayoutPaddingTop
                - mPageLayoutPaddingBottom - ((mWidgetCountY - 1) * mWidgetHeightGap)) / mWidgetCountY);

        // 这里是计算Widget的数目和每页数目,用于后面计算WIdget的预览图
        int offset = page * numItemsPerPage;
        for (int i = offset; i < Math.min(offset + numItemsPerPage,
                mWidgets.size()); ++i) {
            items.add(mWidgets.get(i));
        }

        //获取Widget信息,填充到PagedViewWidget对象里面
        final PagedViewGridLayout layout = (PagedViewGridLayout) getPageAt(page
                + mNumAppsPages);
        layout.setColumnCount(layout.getCellCountX());
     //遍历所有widget和快捷方式
for (int i = 0; i < items.size(); ++i) { Object rawInfo = items.get(i); PendingAddItemInfo createItemInfo = null; PagedViewWidget widget = (PagedViewWidget) mLayoutInflater.inflate( R.layout.apps_customize_widget, layout, false);
        //Widget信息
if (rawInfo instanceof AppWidgetProviderInfo) { // Fill in the widget information AppWidgetProviderInfo info = (AppWidgetProviderInfo) rawInfo; createItemInfo = new PendingAddWidgetInfo(info, null, null); int[] cellSpans = mLauncher.getSpanForWidget(info, null); widget.applyFromAppWidgetProviderInfo(info, -1, cellSpans, mHolographicOutlineHelper); widget.setTag(createItemInfo); }
        //快捷方式
        else if (rawInfo instanceof ResolveInfo) { // Fill in the shortcuts information ResolveInfo info = (ResolveInfo) rawInfo; createItemInfo = new PendingAddItemInfo(); createItemInfo.itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT; createItemInfo.componentName = new ComponentName( info.activityInfo.packageName, info.activityInfo.name); widget.applyFromResolveInfo(mPackageManager, info, mHolographicOutlineHelper); widget.setTag(createItemInfo); } widget.setOnClickListener(this); widget.setOnLongClickListener(this); widget.setOnTouchListener(this); widget.setOnKeyListener(this); //计算每个Widget的位置和布局信息 int ix = i % mWidgetCountX; int iy = i / mWidgetCountX; GridLayout.LayoutParams lp = new GridLayout.LayoutParams( GridLayout.spec(iy, GridLayout.LEFT), GridLayout.spec(ix, GridLayout.TOP)); lp.width = cellWidth; lp.height = cellHeight; lp.setGravity(Gravity.TOP | Gravity.LEFT); if (ix > 0) lp.leftMargin = mWidgetWidthGap; if (iy > 0) lp.topMargin = mWidgetHeightGap; layout.addView(widget, lp); }

  上面是从我们获取的Widget对象里面提取Widget信息,包括位置,最小长宽和预览图。这里分开了Widget和快捷方式,这两种处理稍有不同,可以根据上面代码对比。下面以Widget为例,说说如何生成界面显示的效果。

 

4、Widget预览图

  其实界面上我们看到的Widget预览图也是一个布局生成的,就是一个LinearLayout,下面我们简单看看布局文件R.layout.apps_customize_widget:

//Edited by mythou
//http://www.cnblogs.com/mythou/
<com.android.launcher2.PagedViewWidget
    android:background="@drawable/focusable_view_bg"
    android:focusable="true">

    <LinearLayout
        android:orientation="horizontal">
        <!--Widget名称和占用空间-->
        <TextView 
            android:textSize="20sp" />

        <TextView 
            android:textSize="30sp" />
    </LinearLayout>

    <!-- Widget的预览图-->
    <com.android.launcher2.PagedViewWidgetImageView
        android:id="@+id/widget_preview"
        android:scaleType="matrix" />

</com.android.launcher2.PagedViewWidget>

  上面是Widget预览图的布局(我这里删除了很多属性,只是给个布局示意),主要就是用了两个TextView和一个ImageView实现,预览图的ImageView被重载了,实现了其他功能。根部局的LinearLayout也被重载,加入其他功能。这里不针对这两个类详细分析,PagedViewWidget里面实现了较多功能,包括主要的重绘功能。PagedViewWidgetImageView基本没有做什么事,可以直接当做ImageView使用。

  上面的信息初始化过程,就是加载了这个布局,然后生成对应的对象,然后设置各种信息以及动作监听器。

//Edited by mythou
//http://www.cnblogs.com/mythou/
PagedViewWidget widget = (PagedViewWidget) mLayoutInflater.inflate(
                    R.layout.apps_customize_widget, layout, false);

 

5、结语

  从收集系统信息到初始化相关信息到生成对象大概就是这个过程。Widget缩略图生成过程比较复杂,这个下次再说吧,今天大伙早点休息,七夕快乐!

 

2013-8-13

Edited by 泡泡糖

 

系列文章:

Android Launcher分析和修改1——Launcher默认界面配置(default_workspace)

Android Launcher分析和修改2——Icon修改、界面布局调整、壁纸设置

Android Launcher分析和修改3——Launcher启动和初始化

Android Launcher分析和修改4——初始化加载数据

Android Launcher分析和修改5——HotSeat分析

Android Launcher分析和修改6——页面滑动(PagedView

Android Launcher分析和修改7——AllApp全部应用列表(AppsCustomizeTabHost)

Android Launcher分析和修改8——AllAPP界面拖拽元素(PagedViewWithDraggableItems)

Android Launcher分析和修改9——Launcher启动APP流程

Android Launcher分析和修改10——HotSeat深入进阶

Android Launcher分析和修改11——自定义分页指示器(paged_view_indicator)

 

 

Edited by mythou

原创博文,转载请标明出处:http://www.cnblogs.com/mythou/p/3256212.html