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

来源:互联网 发布:环球人物和看天下知乎 编辑:程序博客网 时间:2024/05/22 09:48

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

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

01if (mWorkspace.allowLongPress()) {  
02    if (cellInfo.cell == null) {  
03        if (cellInfo.valid) {  
04            // User long pressed on empty space  
05            mWorkspace.setAllowLongPress(false);  
06            mWorkspace.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS,  
07                    HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);  
08            showAddDialog(cellInfo);  
09        }  
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),寻找到:

1private 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)方法,代码如下:

01@Override 
02protected Dialog onCreateDialog(int id) {  
03    switch (id) {  
04        case DIALOG_CREATE_SHORTCUT:  
05            return new CreateShortcut().createDialog();  
06        case DIALOG_RENAME_FOLDER:  
07            return new RenameFolder().createDialog();  
08    }  
09   
10    return super.onCreateDialog(id);  
11}

跳转到了CreateShortcut()的createDialog()方法:

01Dialog createDialog() {  
02    mWaitingForResult = true;   
03    mAdapter = new AddAdapter(Launcher.this);   
04    final AlertDialog.Builder builder = newAlertDialog.Builder(Launcher.this);      
05    builder.setTitle(getString(R.string.menu_item_add_item));  
06    builder.setAdapter(mAdapter, this);    
07    builder.setInverseBackgroundForced(true);   
08    AlertDialog dialog = builder.create();  
09    dialog.setOnCancelListener(this);  
10    dialog.setOnDismissListener(this);  
11    dialog.setOnShowListener(this);  
12   
13    return dialog;  
14}

这里可以看到一个 AddAdapter类,跳转去看看,这个就是定义长按后出现的对话框的内容:

1public static final int ITEM_SHORTCUT = 0;
2public static final int ITEM_APPWIDGET = 1;
3public static final int ITEM_LIVE_FOLDER = 2;
4public static final int ITEM_WALLPAPER = 3;

如果我们需要在原来的对话框中添加新的内容,那么首先需要修改的就是这里,我们回到之前的地方接着往下走,dialog响应的点击事件,public void onClick(DialogInterface dialog, int which) :

01case AddAdapter.ITEM_APPWIDGET: {
02    int appWidgetId = Launcher.this.mAppWidgetHost.allocateAppWidgetId();
03    //这里生成了一个appWidgetId,供后面绑定AppWidgetProvider使用
04    Intent pickIntent = new Intent(AppWidgetManager.ACTION_APPWIDGET_PICK);
05    //新建一个intent,该intent是打开一个现实Widgets列表的activity,该activity对应类AppWidgetPickActivity  
06    pickIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
07    // start the pick activity
08    //设置EXTRA_APPWIDGET_ID            
09    startActivityForResult(pickIntent, REQUEST_PICK_APPWIDGET);
10    break;
11}

这里看到点击widget条目之后,跳转打开一个新的pickIntent,其实际运行的为packages/apps/Settings/src/com/android/settings/AppWidgetPickActivity.java:

先在onCreate方法中创建了一个InstalledAppWidgets列表,该列表就是我们在界面上能见到的所有widgets

在点击一个widgets,进入AppWidgetPickActivity.onClick事件监听,注意阅读该方法代码,它会进入else

1if (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);
5else {
6    try {
7        mAppWidgetManager.bindAppWidgetId(mAppWidgetId, intent.getComponent());
8        //绑定选中的桌面组件与mAppWidgetId
9        result = RESULT_OK;//设置返回结果为ok

activity执行结束后面都会进入launcher.onActivityResult,查看该函数方法有两个关键的case:

1case REQUEST_PICK_APPWIDGET:
2     addAppWidget(data);
3       break;
4case REQUEST_CREATE_APPWIDGET:
5     completeAddAppWidget(data, mAddItemCellInfo);

接着跳转到launcher的addAppWidget(Intent data)里data为传递来的appWidgetId:

01void addAppWidget(Intent data) {
02        // TODO: catch bad widget exception when sent
03        int appWidgetId = data.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1);
04        AppWidgetProviderInfo appWidget = mAppWidgetManager.getAppWidgetInfo(appWidgetId);
05 //先判断是否有配置页
06        if (appWidget.configure != null) {
07            // Launch over to configure widget, if needed
08            Intent intent = newIntent(AppWidgetManager.ACTION_APPWIDGET_CONFIGURE);
09            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的添加。

01private void completeAddAppWidget(Intent data, CellLayout.CellInfo cellInfo) {
02        Bundle extras = data.getExtras();
03        int appWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, -1);
04        if (LOGD) Log.d(TAG, "dumping extras content=" + extras.toString());
05 //由appWidgetId获取widget的信息,例如大小等
06        AppWidgetProviderInfo appWidgetInfo = mAppWidgetManager.getAppWidgetInfo(appWidgetId);
07        // Calculate the grid spans needed to fit this widget
08        CellLayout layout = (CellLayout) mWorkspace.getChildAt(cellInfo.screen);
09        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 = newLauncherAppWidgetInfo(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        }
原创粉丝点击