laucher添加widget过程

来源:互联网 发布:知乎登录 编辑:程序博客网 时间:2024/06/05 17:49

 最近打算研究下android的widget相关问题,并把一些心得在此稍作记录,哈哈,等研究完成了,如果有必要的话,也会把改动的源码贴出来,以飨读者。今天先来看看launcher2中添加widget的流程。

    添加widget首先需要在laucher的空白处长按,所以首先定位在laucher的 public boolean onLongClick(View v) 中,看到:

[java] view plain copy
  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),寻找到:

[java] view plain copy
  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)方法,代码如下:

[java] view plain copy
  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()方法:

[java] view plain copy
  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类,跳转去看看,这个就是定义长按后出现的对话框的内容:

[c-sharp] view plain copy
  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) :

[java] view plain copy
  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

[java] view plain copy
  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:

[java] view plain copy
  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:

[java] view plain copy
  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);

 

 

[java] view plain copy
  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的添加。

 

[java] view plain copy
  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.