最近打算研究下android的widget相关问题,并把一些心得在此稍作记录,哈哈,等研究完成了,如果有必要的话,也会把改动的源码贴出来,以飨读者。今天先来看看launcher2中添加widget的流程。
添加widget首先需要在laucher的空白处长按,所以首先定位在laucher的 public boolean onLongClick(View v) 中,看到:
- if (mWorkspace.allowLongPress()) {
- if (cellInfo.cell == null) {
- if (cellInfo.valid) {
-
- mWorkspace.setAllowLongPress(false);
- mWorkspace.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS,
- HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
- showAddDialog(cellInfo);
- }
- } else {
- if (!(cellInfo.cell instanceof Folder)) {
-
- mWorkspace.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS,
- HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
- mWorkspace.startDrag(cellInfo);
- }
- }
- }
可以看到跳转到了showAddDialog(cellInfo),寻找到:
- 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)方法,代码如下:
- @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()方法:
- 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类,跳转去看看,这个就是定义长按后出现的对话框的内容:
- 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) :
- case AddAdapter.ITEM_APPWIDGET: {
- int appWidgetId = Launcher.this.mAppWidgetHost.allocateAppWidgetId();
-
- Intent pickIntent = new Intent(AppWidgetManager.ACTION_APPWIDGET_PICK);
-
- pickIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
-
-
- break;
- }
这里看到点击widget条目之后,跳转打开一个新的pickIntent,其实际运行的为packages/apps/Settings/src/com/android/settings/AppWidgetPickActivity.java:
先在onCreate方法中创建了一个InstalledAppWidgets列表,该列表就是我们在界面上能见到的所有widgets。
在点击一个widgets,进入AppWidgetPickActivity.onClick事件监听,注意阅读该方法代码,它会进入else:
- if (intent.getExtras() != null) {
-
-
- setResultData(RESULT_OK, intent);
- } else {
- try {
- mAppWidgetManager.bindAppWidgetId(mAppWidgetId, intent.getComponent());
-
- result = RESULT_OK;
activity执行结束后面都会进入launcher.onActivityResult,查看该函数方法有两个关键的case:
- case REQUEST_PICK_APPWIDGET:
- addAppWidget(data);
- break;
- case REQUEST_CREATE_APPWIDGET:
- completeAddAppWidget(data, mAddItemCellInfo);
接着跳转到launcher的addAppWidget(Intent data)里data为传递来的appWidgetId:
- void addAppWidget(Intent data) {
-
- int appWidgetId = data.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1);
- AppWidgetProviderInfo appWidget = mAppWidgetManager.getAppWidgetInfo(appWidgetId);
-
- if (appWidget.configure != null) {
-
- 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 {
-
- 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);
- @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的添加。
- 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());
-
- AppWidgetProviderInfo appWidgetInfo = mAppWidgetManager.getAppWidgetInfo(appWidgetId);
-
- CellLayout layout = (CellLayout) mWorkspace.getChildAt(cellInfo.screen);
- int[] spans = layout.rectToCell(appWidgetInfo.minWidth, appWidgetInfo.minHeight);
-
- final int[] xy = mCellCoordinates;
- if (!findSlot(cellInfo, xy, spans[0], spans[1])) {
- if (appWidgetId != -1) mAppWidgetHost.deleteAppWidgetId(appWidgetId);
- return;
- }
-
- 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);
-
- 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());
- }
-