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

添加widget首先需要在laucher的空白处长按,所以首先定位在laucher的 public boolean onLongClick(View v) 中,看到:
[java] view plaincopy
if (mWorkspace.allowLongPress()) {
if (cellInfo.cell == null) {
if (cellInfo.valid) {
// User long pressed on empty space
mWorkspace.setAllowLongPress(false);
mWorkspace.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS,
HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
showAddDialog(cellInfo);
}
} else {
if (!(cellInfo.cell instanceof Folder)) {
// User long pressed on an item
mWorkspace.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS,
HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
mWorkspace.startDrag(cellInfo);
}
}
}

可以看到跳转到了showAddDialog(cellInfo),寻找到:
[java] view plaincopy
private void showAddDialog(CellLayout.CellInfo cellInfo) {
mAddItemCellInfo = cellInfo;
mWaitingForResult = true;
showDialog(DIALOG_CREATE_SHORTCUT);
}

可以看到他携带着DIALOG_CREATE_SHORTCUT参数创建了一个Dialog,携带参数跳入Launcher.java的父类Activity.java的showDialog()方法,最终到达Launcher.java的onCreateDialog(int id)方法,代码如下:
[java] view plaincopy
@Override
protected Dialog onCreateDialog(int id) {
switch (id) {
case DIALOG_CREATE_SHORTCUT:
return new CreateShortcut().createDialog();
case DIALOG_RENAME_FOLDER:
return new RenameFolder().createDialog();
}

return super.onCreateDialog(id);
}

跳转到了CreateShortcut()的createDialog()方法:
[java] view plaincopy
Dialog createDialog() {
mWaitingForResult = true;
mAdapter = new AddAdapter(Launcher.this);
final AlertDialog.Builder builder = new AlertDialog.Builder(Launcher.this); builder.setTitle(getString(R.string.menu_item_add_item));
builder.setAdapter(mAdapter, this);
builder.setInverseBackgroundForced(true);
AlertDialog dialog = builder.create();
dialog.setOnCancelListener(this);
dialog.setOnDismissListener(this);
dialog.setOnShowListener(this);

return dialog;
}

这里可以看到一个 AddAdapter类,跳转去看看,这个就是定义长按后出现的对话框的内容:
[c-sharp] view plaincopy
public static final int ITEM_SHORTCUT = 0;
public static final int ITEM_APPWIDGET = 1;
public static final int ITEM_LIVE_FOLDER = 2;
public static final int ITEM_WALLPAPER = 3;

如果我们需要在原来的对话框中添加新的内容,那么首先需要修改的就是这里,我们回到之前的地方接着往下走,dialog响应的点击事件,public void onClick(DialogInterface dialog, int which) :
[java] view plaincopy
case AddAdapter.ITEM_APPWIDGET: {
int appWidgetId = Launcher.this.mAppWidgetHost.allocateAppWidgetId();
//这里生成了一个appWidgetId,供后面绑定AppWidgetProvider使用
Intent pickIntent = new Intent(AppWidgetManager.ACTION_APPWIDGET_PICK);
//新建一个intent,该intent是打开一个现实Widgets列表的activity,该activity对应类AppWidgetPickActivity
pickIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
// start the pick activity
//设置EXTRA_APPWIDGET_ID startActivityForResult(pickIntent, REQUEST_PICK_APPWIDGET);
break;
}


这里看到点击widget条目之后,跳转打开一个新的pickIntent,其实际运行的为packages/apps/Settings/src/com/android/settings/AppWidgetPickActivity.java:
先在onCreate方法中创建了一个InstalledAppWidgets列表,该列表就是我们在界面上能见到的所有widgets。
在点击一个widgets,进入AppWidgetPickActivity.onClick事件监听,注意阅读该方法代码,它会进入else:
[java] view plaincopy
if (intent.getExtras() != null) {
// If there are any extras, it's because this entry is custom.
// Don't try to bind it, just pass it back to the app.
setResultData(RESULT_OK, intent);
} else {
try {
mAppWidgetManager.bindAppWidgetId(mAppWidgetId, intent.getComponent());
//绑定选中的桌面组件与mAppWidgetId
result = RESULT_OK;//设置返回结果为ok

activity执行结束后面都会进入launcher.onActivityResult,查看该函数方法有两个关键的case:
[java] view plaincopy
case REQUEST_PICK_APPWIDGET:
addAppWidget(data);
break;
case REQUEST_CREATE_APPWIDGET:
completeAddAppWidget(data, mAddItemCellInfo);


接着跳转到launcher的addAppWidget(Intent data)里data为传递来的appWidgetId:
[java] view plaincopy
void addAppWidget(Intent data) {
// TODO: catch bad widget exception when sent
int appWidgetId = data.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1);
AppWidgetProviderInfo appWidget = mAppWidgetManager.getAppWidgetInfo(appWidgetId);
//先判断是否有配置页
if (appWidget.configure != null) {
// Launch over to configure widget, if needed
Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_CONFIGURE);
intent.setComponent(appWidget.configure);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
startActivityForResultSafely(intent, REQUEST_CREATE_APPWIDGET);
} else {
// Otherwise just add it
onActivityResult(REQUEST_CREATE_APPWIDGET, Activity.RESULT_OK, data);
}
}


通过onActivityResult(REQUEST_CREATE_APPWIDGET, Activity.RESULT_OK, data);跳转回launcher.onActivityResult的

case REQUEST_CREATE_APPWIDGET:
completeAddAppWidget(data, mAddItemCellInfo);


[java] view plaincopy
@param data The intent describing the appWidgetId.
* @param cellInfo The position on screen where to create the widget.
*/
private void completeAddAppWidget(Intent data, CellLayout.CellInfo cellInfo)

在 completeAddAppWidget(data, mAddItemCellInfo)中完成widget的添加。

[java] view plaincopy
private void completeAddAppWidget(Intent data, CellLayout.CellInfo cellInfo) {
Bundle extras = data.getExtras();
int appWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, -1);
if (LOGD) Log.d(TAG, "dumping extras content=" + extras.toString());
//由appWidgetId获取widget的信息,例如大小等
AppWidgetProviderInfo appWidgetInfo = mAppWidgetManager.getAppWidgetInfo(appWidgetId);
// Calculate the grid spans needed to fit this widget
CellLayout layout = (CellLayout) mWorkspace.getChildAt(cellInfo.screen);
int[] spans = layout.rectToCell(appWidgetInfo.minWidth, appWidgetInfo.minHeight);
// Try finding open space on Launcher screen
final int[] xy = mCellCoordinates;
if (!findSlot(cellInfo, xy, spans[0], spans[1])) {
if (appWidgetId != -1) mAppWidgetHost.deleteAppWidgetId(appWidgetId);
return;
}
// Build Launcher-specific widget info and save to database
LauncherAppWidgetInfo launcherInfo = new LauncherAppWidgetInfo(appWidgetId);
launcherInfo.spanX = spans[0];
launcherInfo.spanY = spans[1];
LauncherModel.addItemToDatabase(this, launcherInfo,
LauncherSettings.Favorites.CONTAINER_DESKTOP,
mWorkspace.getCurrentScreen(), xy[0], xy[1], false);
if (!mRestoring) {
mDesktopItems.add(launcherInfo);
// Perform actual inflation because we're live
launcherInfo.hostView = mAppWidgetHost.createView(this, appWidgetId, appWidgetInfo);
launcherInfo.hostView.setAppWidget(appWidgetId, appWidgetInfo);
launcherInfo.hostView.setTag(launcherInfo);
mWorkspace.addInCurrentScreen(launcherInfo.hostView, xy[0], xy[1],
launcherInfo.spanX, launcherInfo.spanY, isWorkspaceLocked());
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值