分享

【转】探秘widget之launcher添加widget的流程分析

 techres 2012-07-30
最近打算研究下android的widget相关问题,并把一些心得在此稍作记录,哈哈,等研究完成了,如果有必要的话,也会把改动的源码贴出来,以飨读者。今天先来看看launcher2中添加widget的流程。
    添加widget首先需要在laucher的空白处长按,所以首先定位在laucher的 public boolean onLongClick(View v) 中,看到:
  1. if (mWorkspace.allowLongPress()) {   
  2.     if (cellInfo.cell == null) {   
  3.         if (cellInfo.valid) {   
  4.             // User long pressed on empty space   
  5.             mWorkspace.setAllowLongPress(false);   
  6.             mWorkspace.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS,   
  7.                     HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);   
  8.             showAddDialog(cellInfo);   
  9.         }   
  10.     } else {   
  11.         if (!(cellInfo.cell instanceof Folder)) {   
  12.             // User long pressed on an item   
  13.             mWorkspace.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS,   
  14.                     HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);   
  15.             mWorkspace.startDrag(cellInfo);   
  16.         }   
  17.     }   
  18. }  
复制代码
可以看到跳转到了showAddDialog(cellInfo),寻找到:
  1. private void showAddDialog(CellLayout.CellInfo cellInfo) {   
  2.     mAddItemCellInfo = cellInfo;   
  3.     mWaitingForResult = true;   
  4.     showDialog(DIALOG_CREATE_SHORTCUT);   
  5. }  
复制代码
可以看到他携带着DIALOG_CREATE_SHORTCUT参数创建了一个Dialog,携带参数跳入Launcher.java的父类Activity.java的showDialog()方法,最终到达Launcher.java的onCreateDialog(int id)方法,代码如下:
  1. @Override  
  2. protected Dialog onCreateDialog(int id) {   
  3.     switch (id) {   
  4.         case DIALOG_CREATE_SHORTCUT:   
  5.             return new CreateShortcut().createDialog();   
  6.         case DIALOG_RENAME_FOLDER:   
  7.             return new RenameFolder().createDialog();   
  8.     }   
  9.   
  10.     return super.onCreateDialog(id);   
  11. }  
复制代码
跳转到了CreateShortcut()的createDialog()方法:
  1. Dialog createDialog() {   
  2.     mWaitingForResult = true;   
  3.     mAdapter = new AddAdapter(Launcher.this);   
  4.     final AlertDialog.Builder builder = new AlertDialog.Builder(Launcher.this);       builder.setTitle(getString(R.string.menu_item_add_item));   
  5.     builder.setAdapter(mAdapter, this);     
  6.     builder.setInverseBackgroundForced(true);   
  7.     AlertDialog dialog = builder.create();   
  8.     dialog.setOnCancelListener(this);   
  9.     dialog.setOnDismissListener(this);   
  10.     dialog.setOnShowListener(this);   
  11.   
  12.     return dialog;   
  13. }  
复制代码
这里可以看到一个  AddAdapter类,跳转去看看,这个就是定义长按后出现的对话框的内容:
  1. public static final int ITEM_SHORTCUT = 0;
  2.     public static final int ITEM_APPWIDGET = 1;
  3.     public static final int ITEM_LIVE_FOLDER = 2;
  4.     public static final int ITEM_WALLPAPER = 3;
复制代码
如果我们需要在原来的对话框中添加新的内容,那么首先需要修改的就是这里,我们回到之前的地方接着往下走,dialog响应的点击事件,public void onClick(DialogInterface dialog, int which) :
  1. case AddAdapter.ITEM_APPWIDGET: {
  2.                     int appWidgetId = Launcher.this.mAppWidgetHost.allocateAppWidgetId();
  3. //这里生成了一个appWidgetId,供后面绑定AppWidgetProvider使用
  4.                     Intent pickIntent = new Intent(AppWidgetManager.ACTION_APPWIDGET_PICK);
  5. //新建一个intent,该intent是打开一个现实Widgets列表的activity,该activity对应类AppWidgetPickActivity   
  6.                 pickIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
  7.                     // start the pick activity
  8.        //设置EXTRA_APPWIDGET_ID             startActivityForResult(pickIntent, REQUEST_PICK_APPWIDGET);
  9.                     break;
  10.                 }
复制代码
这里看到点击widget条目之后,跳转打开一个新的pickIntent,其实际运行的为packages/apps/Settings/src/com/android/settings/AppWidgetPickActivity.java:
先在onCreate方法中创建了一个InstalledAppWidgets列表,该列表就是我们在界面上能见到的所有widgets。
在点击一个widgets,进入AppWidgetPickActivity.onClick事件监听,注意阅读该方法代码,它会进入else
  1. if (intent.getExtras() != null) {
  2.             // If there are any extras, it's because this entry is custom.
  3.             // Don't try to bind it, just pass it back to the app.
  4.             setResultData(RESULT_OK, intent);
  5.         } else {
  6.             try {
  7.                 mAppWidgetManager.bindAppWidgetId(mAppWidgetId, intent.getComponent());
  8. //绑定选中的桌面组件与mAppWidgetId
  9.         result = RESULT_OK;//设置返回结果为ok
复制代码
activity执行结束后面都会进入launcher.onActivityResult,查看该函数方法有两个关键的case:
  1. case REQUEST_PICK_APPWIDGET:
  2.      addAppWidget(data);
  3.        break;
  4. case REQUEST_CREATE_APPWIDGET:
  5.      completeAddAppWidget(data, mAddItemCellInfo);
复制代码
接着跳转到launcher的addAppWidget(Intent data)里data为传递来的appWidgetId:
  1. void addAppWidget(Intent data) {
  2.         // TODO: catch bad widget exception when sent
  3.         int appWidgetId = data.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1);
  4.         AppWidgetProviderInfo appWidget = mAppWidgetManager.getAppWidgetInfo(appWidgetId);
  5. //先判断是否有配置页
  6.         if (appWidget.configure != null) {
  7.             // Launch over to configure widget, if needed
  8.             Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_CONFIGURE);
  9.             intent.setComponent(appWidget.configure);
  10.             intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
  11.             startActivityForResultSafely(intent, REQUEST_CREATE_APPWIDGET);
  12.         } else {
  13.             // Otherwise just add it
  14.             onActivityResult(REQUEST_CREATE_APPWIDGET, Activity.RESULT_OK, data);
  15.         }
  16.     }
复制代码
通过onActivityResult(REQUEST_CREATE_APPWIDGET, Activity.RESULT_OK, data);跳转回launcher.onActivityResult的

case REQUEST_CREATE_APPWIDGET:
          completeAddAppWidget(data, mAddItemCellInfo);
  1. @param data The intent describing the appWidgetId.
  2.      * @param cellInfo The position on screen where to create the widget.
  3.      */
  4.     private void completeAddAppWidget(Intent data, CellLayout.CellInfo cellInfo)
复制代码
在 completeAddAppWidget(data, mAddItemCellInfo)中完成widget的添加。
  1. private void completeAddAppWidget(Intent data, CellLayout.CellInfo cellInfo) {
  2.         Bundle extras = data.getExtras();
  3.         int appWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, -1);
  4.         if (LOGD) Log.d(TAG, "dumping extras content=" + extras.toString());
  5. //由appWidgetId获取widget的信息,例如大小等
  6.         AppWidgetProviderInfo appWidgetInfo = mAppWidgetManager.getAppWidgetInfo(appWidgetId);
  7.         // Calculate the grid spans needed to fit this widget
  8.         CellLayout layout = (CellLayout) mWorkspace.getChildAt(cellInfo.screen);
  9.         int[] spans = layout.rectToCell(appWidgetInfo.minWidth, appWidgetInfo.minHeight);
  10.         // Try finding open space on Launcher screen
  11.         final int[] xy = mCellCoordinates;
  12.         if (!findSlot(cellInfo, xy, spans[0], spans[1])) {
  13.             if (appWidgetId != -1) mAppWidgetHost.deleteAppWidgetId(appWidgetId);
  14.             return;
  15.         }
  16.         // Build Launcher-specific widget info and save to database
  17.         LauncherAppWidgetInfo launcherInfo = new LauncherAppWidgetInfo(appWidgetId);
  18.         launcherInfo.spanX = spans[0];
  19.         launcherInfo.spanY = spans[1];
  20.         LauncherModel.addItemToDatabase(this, launcherInfo,
  21.                 LauncherSettings.Favorites.CONTAINER_DESKTOP,
  22.                 mWorkspace.getCurrentScreen(), xy[0], xy[1], false);
  23.         if (!mRestoring) {
  24.             mDesktopItems.add(launcherInfo);
  25.             // Perform actual inflation because we're live
  26.             launcherInfo.hostView = mAppWidgetHost.createView(this, appWidgetId, appWidgetInfo);
  27.             launcherInfo.hostView.setAppWidget(appWidgetId, appWidgetInfo);
  28.             launcherInfo.hostView.setTag(launcherInfo);
  29.             mWorkspace.addInCurrentScreen(launcherInfo.hostView, xy[0], xy[1],
  30.                     launcherInfo.spanX, launcherInfo.spanY, isWorkspaceLocked());
  31.         }
  32.    
复制代码

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多